diff options
author | Uros Majstorovic <majstor@majstor.org> | 2020-08-05 03:39:22 +0200 |
---|---|---|
committer | Uros Majstorovic <majstor@majstor.org> | 2020-08-05 03:39:22 +0200 |
commit | cf7c06297d04bade9cd04c056f9ed510e64dd7bd (patch) | |
tree | a3b8cc23574b98e10874b51d33c9fe1bfc012663 /fw | |
parent | 5cd610a07468137066ea4daa5176c3e7045113b0 (diff) |
code -> fw
Diffstat (limited to 'fw')
175 files changed, 15550 insertions, 0 deletions
diff --git a/fw/esp32/LICENSE b/fw/esp32/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/fw/esp32/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/fw/esp32/Makefile b/fw/esp32/Makefile new file mode 100644 index 0000000..eb26385 --- /dev/null +++ b/fw/esp32/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := eos-app + +include $(IDF_PATH)/make/project.mk + diff --git a/fw/esp32/components/eos/at_cmd.c b/fw/esp32/components/eos/at_cmd.c new file mode 100644 index 0000000..4712ad7 --- /dev/null +++ b/fw/esp32/components/eos/at_cmd.c @@ -0,0 +1,164 @@ +#include <stdlib.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/semphr.h> +#include <esp_log.h> + +#include "eos.h" + +#include "cell.h" +#include "at_cmd.h" + +static const char *TAG = "EOS ATCMD"; + +typedef struct ATURCItem { + regex_t re; + at_urc_cb_t cb; + char pattern[AT_SIZE_PATTERN]; +} ATURCItem; + +typedef struct ATURCList { + ATURCItem item[AT_SIZE_URC_LIST]; + int len; +} ATURCList; + +static ATURCList urc_list; +static ATURCItem *urc_curr; +static SemaphoreHandle_t mutex; + +static char at_buf[EOS_CELL_UART_SIZE_BUF]; + +void at_init(void) { + memset(&urc_list, 0, sizeof(ATURCList)); + + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); +} + +int at_urc_process(char *urc) { + regmatch_t match[AT_SIZE_NMATCH]; + at_urc_cb_t cb = NULL; + regmatch_t *m = NULL; + + xSemaphoreTake(mutex, portMAX_DELAY); + + if (urc_curr == NULL) { + int i; + + for (i=0; i<urc_list.len; i++) { + if (regexec(&urc_list.item[i].re, urc, AT_SIZE_NMATCH, match, 0) == 0) { + urc_curr = &urc_list.item[i]; + m = match; + break; + } + } + } + if (urc_curr) cb = urc_curr->cb; + + xSemaphoreGive(mutex); + + if (cb) { + int r = cb(urc, m); + + if (r != AT_URC_MORE) { + xSemaphoreTake(mutex, portMAX_DELAY); + urc_curr = NULL; + xSemaphoreGive(mutex); + } + ESP_LOGD(TAG, "URC Processed: %s", urc); + return 1; + } + + ESP_LOGD(TAG, "URC NOT Processed: %s", urc); + return 0; +} + +int at_urc_insert(char *pattern, at_urc_cb_t cb, int flags) { + int r; + int rv = EOS_OK; + + if (strlen(pattern) >= AT_SIZE_PATTERN) return EOS_ERR; + + xSemaphoreTake(mutex, portMAX_DELAY); + + r = regcomp(&urc_list.item[urc_list.len].re, pattern, flags); + if (r) rv = EOS_ERR; + + if (!rv && (urc_list.len == AT_SIZE_URC_LIST)) rv = EOS_ERR_FULL; + if (!rv) { + strcpy(urc_list.item[urc_list.len].pattern, pattern); + urc_list.item[urc_list.len].cb = cb; + urc_list.len++; + } + + xSemaphoreGive(mutex); + + return rv; +} + +int at_urc_delete(char *pattern) { + int i; + int rv = EOS_ERR_NOTFOUND; + + xSemaphoreTake(mutex, portMAX_DELAY); + + for (i=0; i<urc_list.len; i++) { + if ((strcmp(pattern, urc_list.item[i].pattern) == 0)) { + if (i != urc_list.len - 1) memmove(&urc_list.item[i], &urc_list.item[i + 1], (urc_list.len - i - 1) * sizeof(ATURCItem)); + urc_list.len--; + memset(&urc_list.item[urc_list.len], 0, sizeof(ATURCItem)); + if (urc_curr) { + if (urc_curr == &urc_list.item[i]) { + urc_curr = NULL; + } else if (urc_curr > &urc_list.item[i]) { + urc_curr--; + } + } + rv = EOS_OK; + break; + } + } + + xSemaphoreGive(mutex); + + return rv; +} + +void at_cmd(char *cmd) { + eos_modem_write(cmd, strlen(cmd)); + ESP_LOGD(TAG, "Cmd: %s", cmd); +} + +int at_expect(char *str_ok, char *str_err, uint32_t timeout) { + int rv; + regex_t re_ok; + regex_t re_err; + uint32_t e = 0; + uint64_t t_start = esp_timer_get_time(); + + if (str_ok) { + rv = regcomp(&re_ok, str_ok, REG_EXTENDED | REG_NOSUB); + if (rv) return EOS_ERR; + } + + if (str_err) { + rv = regcomp(&re_err, str_err, REG_EXTENDED | REG_NOSUB); + if (rv) return EOS_ERR; + } + + do { + rv = eos_modem_readln(at_buf, sizeof(at_buf), timeout - e); + ESP_LOGD(TAG, "Expect: %s", at_buf); + + if (at_buf[0] != '\0') { + if (!rv && str_ok && (regexec(&re_ok, at_buf, 0, NULL, 0) == 0)) return 1; + if (!rv && str_err && (regexec(&re_err, at_buf, 0, NULL, 0) == 0)) return 0; + + at_urc_process(at_buf); + } + + e = (uint32_t)(esp_timer_get_time() - t_start) / 1000; + if (e > timeout) return EOS_ERR_TIMEOUT; + } while (1); +} diff --git a/fw/esp32/components/eos/bq25895.c b/fw/esp32/components/eos/bq25895.c new file mode 100644 index 0000000..0d1bb8d --- /dev/null +++ b/fw/esp32/components/eos/bq25895.c @@ -0,0 +1,60 @@ +#include <stdlib.h> + +#include <esp_log.h> + +#include "eos.h" +#include "i2c.h" + +static const char *TAG = "EOS BQ25895"; + +#define BQ25895_ADDR 0x6A + +void eos_bq25895_set_ilim(void) { + uint8_t data = 0; + eos_i2c_write8(BQ25895_ADDR, 0, 0x1c); + eos_i2c_write8(BQ25895_ADDR, 2, 0x28); + eos_i2c_write8(BQ25895_ADDR, 7, 0x8d); + + data = eos_i2c_read8(BQ25895_ADDR, 0x00); + ESP_LOGI(TAG, "REG00: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x01); + ESP_LOGI(TAG, "REG01: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x02); + ESP_LOGI(TAG, "REG02: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x03); + ESP_LOGI(TAG, "REG03: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x04); + ESP_LOGI(TAG, "REG04: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x05); + ESP_LOGI(TAG, "REG05: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x06); + ESP_LOGI(TAG, "REG06: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x07); + ESP_LOGI(TAG, "REG07: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x08); + ESP_LOGI(TAG, "REG08: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x09); + ESP_LOGI(TAG, "REG09: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0a); + ESP_LOGI(TAG, "REG0A: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0b); + ESP_LOGI(TAG, "REG0B: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0c); + ESP_LOGI(TAG, "REG0C: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0d); + ESP_LOGI(TAG, "REG0D: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0e); + ESP_LOGI(TAG, "REG0E: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x0f); + ESP_LOGI(TAG, "REG0F: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x10); + ESP_LOGI(TAG, "REG10: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x11); + ESP_LOGI(TAG, "REG11: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x12); + ESP_LOGI(TAG, "REG12: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x13); + ESP_LOGI(TAG, "REG13: %02x", data); + data = eos_i2c_read8(BQ25895_ADDR, 0x14); + ESP_LOGI(TAG, "REG14: %02x", data); +} diff --git a/fw/esp32/components/eos/cell.c b/fw/esp32/components/eos/cell.c new file mode 100644 index 0000000..c2e03e1 --- /dev/null +++ b/fw/esp32/components/eos/cell.c @@ -0,0 +1,68 @@ +#include <stdlib.h> +#include <stdint.h> + +#include <esp_log.h> + +#include "eos.h" +#include "net.h" +#include "cell.h" + +static uint8_t cell_mode; + +static void cell_handler(unsigned char _mtype, unsigned char *buffer, uint16_t size) { + uint8_t mtype; + + if (size < 1) return; + mtype = buffer[0]; + switch (mtype & EOS_CELL_MTYPE_MASK) { + case EOS_CELL_MTYPE_DEV: + switch (mtype) { + case EOS_CELL_MTYPE_UART_DATA: + if (eos_modem_get_mode() == EOS_CELL_UART_MODE_RELAY) eos_modem_write(buffer+1, size-1); + break; + + case EOS_CELL_MTYPE_UART_TAKE: + cell_mode = eos_modem_get_mode(); + eos_modem_set_mode(EOS_CELL_UART_MODE_RELAY); + break; + + case EOS_CELL_MTYPE_UART_GIVE: + eos_modem_set_mode(cell_mode); + break; + + case EOS_CELL_MTYPE_PCM_DATA: + eos_cell_pcm_push(buffer+1, size-1); + break; + + case EOS_CELL_MTYPE_PCM_START: + eos_cell_pcm_start(); + break; + + case EOS_CELL_MTYPE_PCM_STOP: + eos_cell_pcm_stop(); + break; + } + break; + + case EOS_CELL_MTYPE_VOICE: + eos_cell_voice_handler(mtype & ~EOS_CELL_MTYPE_MASK, buffer, size); + break; + + case EOS_CELL_MTYPE_SMS: + eos_cell_sms_handler(mtype & ~EOS_CELL_MTYPE_MASK, buffer, size); + break; + + case EOS_CELL_MTYPE_USSD: + eos_cell_ussd_handler(mtype & ~EOS_CELL_MTYPE_MASK, buffer, size); + break; + + case EOS_CELL_MTYPE_DATA: + eos_cell_data_handler(mtype & ~EOS_CELL_MTYPE_MASK, buffer, size); + break; + } +} + +void eos_cell_init(void) { + eos_net_set_handler(EOS_NET_MTYPE_CELL, cell_handler); +} + diff --git a/fw/esp32/components/eos/cell_data.c b/fw/esp32/components/eos/cell_data.c new file mode 100644 index 0000000..6732346 --- /dev/null +++ b/fw/esp32/components/eos/cell_data.c @@ -0,0 +1,20 @@ +#include <stdlib.h> + +#include <esp_log.h> + +#include "eos.h" +#include "cell.h" + +void eos_cell_data_handler(unsigned char mtype, unsigned char *buffer, uint16_t size) { + int rv; + + rv = eos_modem_take(1000); + if (rv) return; + + buffer += 1; + size -= 1; + switch (mtype) { + } + + eos_modem_give(); +} diff --git a/fw/esp32/components/eos/cell_modem.c b/fw/esp32/components/eos/cell_modem.c new file mode 100644 index 0000000..c6d718f --- /dev/null +++ b/fw/esp32/components/eos/cell_modem.c @@ -0,0 +1,767 @@ +#include <stdlib.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/semphr.h> +#include <freertos/task.h> +#include <freertos/queue.h> +#include <netif/ppp/pppos.h> +#include <netif/ppp/pppapi.h> +#include <driver/uart.h> +#include <driver/gpio.h> +#include <esp_sleep.h> +#include <esp_log.h> + +#include "eos.h" +#include "net.h" +#include "power.h" + +#include "at_cmd.h" +#include "cell.h" + +// XXX: PPP reconnect on failure + +#define UART_SIZE_IO_BUF 1024 + +#define UART_GPIO_TXD 16 +#define UART_GPIO_RXD 17 +#define UART_GPIO_DTR 32 +#define UART_GPIO_RI 35 + +#define MODEM_ETYPE_INIT 1 +#define MODEM_ETYPE_RI 2 + +#define AT_CMD_INIT_SIZE 3 + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +static const char *TAG = "EOS MODEM"; + +static char *at_cmd_init[AT_CMD_INIT_SIZE] = { + "AT+CFGRI=1\r", + "AT+CSCLK=1\r", + "AT+CMGF=0\r" +}; + +static SemaphoreHandle_t mutex; + +static QueueHandle_t modem_queue; +static QueueHandle_t uart_queue; + +static char urc_buf[EOS_CELL_UART_SIZE_BUF]; +static char uart_buf[EOS_CELL_UART_SIZE_BUF]; +static size_t uart_buf_len; + +static uint8_t uart_mode = EOS_CELL_UART_MODE_ATCMD; +static SemaphoreHandle_t uart_mutex; + +static char ppp_apn[64]; +static char ppp_user[64]; +static char ppp_pass[64]; +static SemaphoreHandle_t ppp_mutex; + +static ppp_pcb *ppp_handle; +static struct netif ppp_netif; + +typedef enum { + UART_EEVT_MODE = UART_EVENT_MAX +} uart_eevt_type_t; + +typedef struct { + uint8_t type; +} modem_event_t; + +static void modem_atcmd_read(size_t bsize); + +static void uart_data_read(uint8_t mode) { + unsigned char *buf; + int rd; + size_t bsize; + + uart_get_buffered_data_len(UART_NUM_2, &bsize); + switch (mode) { + case EOS_CELL_UART_MODE_ATCMD: + modem_atcmd_read(bsize); + break; + + case EOS_CELL_UART_MODE_PPP: + rd = 0; + + do { + int _rd = eos_modem_read(uart_buf, MIN(bsize - rd, sizeof(uart_buf)), 100); + pppos_input_tcpip(ppp_handle, (uint8_t *)uart_buf, _rd); + rd += _rd; + } while (rd != bsize); + break; + + case EOS_CELL_UART_MODE_RELAY: + rd = 0; + + do { + int _rd; + + buf = eos_net_alloc(); + buf[0] = EOS_CELL_MTYPE_UART_DATA; + _rd = eos_modem_read(buf + 1, MIN(bsize - rd, EOS_NET_SIZE_BUF - 1), 100); + eos_net_send(EOS_NET_MTYPE_CELL, buf, _rd + 1, 0); + rd += _rd; + } while (rd != bsize); + break; + + default: + break; + + } +} + +static void uart_event_task(void *pvParameters) { + char mode = EOS_CELL_UART_MODE_ATCMD; + char _mode = EOS_CELL_UART_MODE_ATCMD; + uart_event_t event; + + xSemaphoreTake(uart_mutex, portMAX_DELAY); + while (1) { + /* Waiting for UART event. + */ + if (xQueueReceive(uart_queue, &event, portMAX_DELAY)) { + switch (event.type) { + case UART_DATA: + /* Event of UART receiving data + */ + if (mode != EOS_CELL_UART_MODE_NONE) uart_data_read(mode); + if ((mode != _mode) && (uart_buf_len == 0)) { + if (_mode == EOS_CELL_UART_MODE_NONE) xSemaphoreGive(uart_mutex); + mode = _mode; + } + break; + + case UART_EEVT_MODE: + /* Mode change + */ + _mode = (char)event.size; + if ((_mode != mode) && ((uart_buf_len == 0) || (mode == EOS_CELL_UART_MODE_NONE))) { + if (mode == EOS_CELL_UART_MODE_NONE) { + xSemaphoreTake(uart_mutex, portMAX_DELAY); + uart_data_read(_mode); + } + if (_mode == EOS_CELL_UART_MODE_NONE) xSemaphoreGive(uart_mutex); + mode = _mode; + } + break; + + default: + break; + } + } + } + vTaskDelete(NULL); +} + +static void IRAM_ATTR uart_ri_isr_handler(void *arg) { + modem_event_t evt; + + evt.type = MODEM_ETYPE_RI; + xQueueSendFromISR(modem_queue, &evt, NULL); +} + +static int modem_atcmd_init(void) { + unsigned char *buf; + int echo_on = 0; + int tries = 3; + int i, r; + int rv = EOS_OK; + + rv = eos_modem_take(1000); + if (rv) return rv; + + do { + at_cmd("AT\r"); + r = at_expect("^AT", "^OK", 1000); + if (r >= 0) { + echo_on = r; + if (echo_on) { + r = at_expect("^OK", NULL, 1000); + } + break; + } + tries--; + } while (tries); + + if (tries == 0) { + eos_modem_give(); + return EOS_ERR_TIMEOUT; + } + + if (echo_on) { + at_cmd("AT&F\r"); + r = at_expect("^AT&F", NULL, 1000); + r = at_expect("^OK", NULL, 1000); + } else { + at_cmd("AT&F\r"); + r = at_expect("^OK", NULL, 1000); + + } + at_cmd("ATE0\r"); + r = at_expect("^ATE0", NULL, 1000); + r = at_expect("^OK", "^ERROR", 1000); + + for (i=0; i<AT_CMD_INIT_SIZE; i++) { + at_cmd(at_cmd_init[i]); + r = at_expect("^OK", "^ERROR", 1000); + } + + buf = eos_net_alloc(); + buf[0] = EOS_CELL_MTYPE_READY; + eos_net_send(EOS_NET_MTYPE_CELL, buf, 1, 0); + + eos_modem_give(); + + return EOS_OK; +} + +static void modem_atcmd_read(size_t bsize) { + char *ln_end; + int rd = 0; + + do { + char *uart_curr = uart_buf + uart_buf_len; + int _rd = eos_modem_read(uart_curr, MIN(bsize - rd, sizeof(uart_buf) - uart_buf_len - 1), 100); + + rd += _rd; + uart_buf_len += _rd; + uart_buf[uart_buf_len] = '\0'; + while ((ln_end = strchr(uart_curr, '\n'))) { + size_t urc_buf_len = ln_end - uart_buf; + + if ((ln_end > uart_buf) && (*(ln_end - 1) == '\r')) urc_buf_len--; + memcpy(urc_buf, uart_buf, urc_buf_len); + urc_buf[urc_buf_len] = '\0'; + + uart_buf_len -= ln_end - uart_buf + 1; + if (uart_buf_len) memmove(uart_buf, ln_end + 1, uart_buf_len); + uart_curr = uart_buf; + uart_buf[uart_buf_len] = '\0'; + + at_urc_process(urc_buf); + } + if (uart_buf_len == sizeof(uart_buf) - 1) { + uart_buf_len = 0; + memcpy(urc_buf, uart_buf, sizeof(urc_buf)); + at_urc_process(urc_buf); + } + } while (rd != bsize); +} + +int modem_urc_init_handler(char *urc, regmatch_t *m) { + modem_event_t evt; + + evt.type = MODEM_ETYPE_INIT; + xQueueSend(modem_queue, &evt, portMAX_DELAY); + + return AT_URC_OK; +} + +static void modem_set_mode(uint8_t mode) { + uart_event_t evt; + + evt.type = UART_EEVT_MODE; + evt.size = mode; + xQueueSend(uart_queue, &evt, portMAX_DELAY); +} + +static void modem_event_task(void *pvParameters) { + modem_event_t evt; + + while (1) { + if (xQueueReceive(modem_queue, &evt, portMAX_DELAY)) { + switch (evt.type) { + case MODEM_ETYPE_INIT: + modem_atcmd_init(); + break; + + case MODEM_ETYPE_RI: + ESP_LOGI(TAG, "URC from RI"); + break; + + default: + break; + } + + /* Obsolete!!! + uint64_t t_start = esp_timer_get_time(); + if (xQueueReceive(modem_queue, &level, 200 / portTICK_RATE_MS) && (level == 1)) { + uint64_t t_end = esp_timer_get_time(); + ESP_LOGI(TAG, "URC:%u", (uint32_t)(t_end - t_start)); + } else { + ESP_LOGI(TAG, "RING"); + } + */ + + } + } + vTaskDelete(NULL); +} + +static char *memstr(char *mem, size_t size, char *str) { + size_t i = 0; + char *max_mem; + + if (str[0] == '\0') return NULL; + + max_mem = mem + size; + + while (mem < max_mem) { + if (*mem != str[i]) { + mem -= i; + i = 0; + } else { + if (str[i+1] == '\0') return mem - i; + i++; + } + mem++; + } + + return NULL; +} + +static uint32_t ppp_output_cb(ppp_pcb *pcb, uint8_t *data, uint32_t len, void *ctx) { + size_t rv; + + xSemaphoreTake(ppp_mutex, portMAX_DELAY); + rv = eos_modem_write(data, len); + xSemaphoreGive(ppp_mutex); + + return rv; +} + +/* PPP status callback */ +static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { + // struct netif *pppif = ppp_netif(pcb); + // LWIP_UNUSED_ARG(ctx); + + switch(err_code) { + case PPPERR_NONE: { + ESP_LOGE(TAG, "status_cb: Connect"); + break; + } + case PPPERR_PARAM: { + ESP_LOGE(TAG, "status_cb: Invalid parameter"); + break; + } + case PPPERR_OPEN: { + ESP_LOGE(TAG, "status_cb: Unable to open PPP session"); + break; + } + case PPPERR_DEVICE: { + ESP_LOGE(TAG, "status_cb: Invalid I/O device for PPP"); + break; + } + case PPPERR_ALLOC: { + ESP_LOGE(TAG, "status_cb: Unable to allocate resources"); + break; + } + case PPPERR_USER: { + ESP_LOGE(TAG, "status_cb: User interrupt"); + break; + } + case PPPERR_CONNECT: { + ESP_LOGE(TAG, "status_cb: Connection lost"); + break; + } + case PPPERR_AUTHFAIL: { + ESP_LOGE(TAG, "status_cb: Failed authentication challenge"); + break; + } + case PPPERR_PROTOCOL: { + ESP_LOGE(TAG, "status_cb: Failed to meet protocol"); + break; + } + case PPPERR_PEERDEAD: { + ESP_LOGE(TAG, "status_cb: Connection timeout"); + break; + } + case PPPERR_IDLETIMEOUT: { + ESP_LOGE(TAG, "status_cb: Idle Timeout"); + break; + } + case PPPERR_CONNECTTIME: { + ESP_LOGE(TAG, "status_cb: Max connect time reached"); + break; + } + case PPPERR_LOOPBACK: { + ESP_LOGE(TAG, "status_cb: Loopback detected"); + break; + } + default: { + ESP_LOGE(TAG, "status_cb: Unknown error code %d", err_code); + break; + } + } +} + +static int ppp_pause(uint32_t timeout, uint8_t retries) { + int done = 0; + int len = 0; + int rv = EOS_OK; + char *ok_str = NULL; + uint64_t t_start; + + timeout += 1000; + xSemaphoreTake(ppp_mutex, portMAX_DELAY); + eos_modem_flush(); + vTaskDelay(1000 / portTICK_PERIOD_MS); + modem_set_mode(EOS_CELL_UART_MODE_NONE); + xSemaphoreTake(uart_mutex, portMAX_DELAY); + at_cmd("+++"); + t_start = esp_timer_get_time(); + + do { + len = eos_modem_read(uart_buf + uart_buf_len, sizeof(uart_buf) - uart_buf_len, 10); + if (len > 0) { + if (uart_buf_len > 5) { + ok_str = memstr(uart_buf + uart_buf_len - 5, len + 5, "\r\nOK\r\n"); + } else { + ok_str = memstr(uart_buf, len + uart_buf_len, "\r\nOK\r\n"); + } + uart_buf_len += len; + } + if (ok_str) { + pppos_input_tcpip(ppp_handle, (uint8_t *)uart_buf, ok_str - uart_buf); + ok_str += 6; + uart_buf_len -= ok_str - uart_buf; + if (uart_buf_len) memmove(uart_buf, ok_str, uart_buf_len); + done = 1; + } else if (uart_buf_len == sizeof(uart_buf)) { + pppos_input_tcpip(ppp_handle, (uint8_t *)uart_buf, sizeof(uart_buf) / 2); + memcpy(uart_buf, uart_buf + sizeof(uart_buf) / 2, sizeof(uart_buf) / 2); + uart_buf_len = sizeof(uart_buf) / 2; + } + if (timeout && !done && ((uint32_t)((esp_timer_get_time() - t_start) / 1000) > timeout)) { + if (!retries) { + modem_set_mode(EOS_CELL_UART_MODE_PPP); + xSemaphoreGive(uart_mutex); + xSemaphoreGive(ppp_mutex); + rv = EOS_ERR_TIMEOUT; + done = 1; + } else { + retries--; + at_cmd("+++"); + t_start = esp_timer_get_time(); + } + } + } while (!done); + + return rv; +} + +static int ppp_resume(void) { + int r; + int rv = EOS_OK; + + at_cmd("ATO\r"); + r = at_expect("^CONNECT", "^(ERROR|NO CARRIER)", 1000); + if (r <= 0) rv = EOS_ERR; + + modem_set_mode(EOS_CELL_UART_MODE_PPP); + xSemaphoreGive(uart_mutex); + xSemaphoreGive(ppp_mutex); + + return rv; +} + +static int ppp_setup(void) { + int r; + char cmd[64]; + int cmd_len = snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"IP\",\"%s\"\r", ppp_apn); + + if ((cmd_len < 0) || (cmd_len >= sizeof(cmd))) return EOS_ERR; + + modem_set_mode(EOS_CELL_UART_MODE_NONE); + r = xSemaphoreTake(uart_mutex, 1000 / portTICK_PERIOD_MS); + if (r == pdFALSE) { + modem_set_mode(uart_mode); + return EOS_ERR_TIMEOUT; + } + + at_cmd(cmd); + r = at_expect("^OK", "^ERROR", 1000); + if (r <= 0) { + modem_set_mode(uart_mode); + xSemaphoreGive(uart_mutex); + return EOS_ERR; + } + + at_cmd("AT+CGDATA=\"PPP\",1\r"); + r = at_expect("^CONNECT", "^(ERROR|\\+CME ERROR|NO CARRIER)", 1000); + if (r <= 0) { + modem_set_mode(uart_mode); + xSemaphoreGive(uart_mutex); + return EOS_ERR; + } + + ppp_handle = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL); + ppp_set_usepeerdns(ppp_handle, 1); + pppapi_set_default(ppp_handle); + pppapi_set_auth(ppp_handle, PPPAUTHTYPE_PAP, ppp_user, ppp_pass); + pppapi_connect(ppp_handle, 0); + + modem_set_mode(EOS_CELL_UART_MODE_PPP); + xSemaphoreGive(uart_mutex); + + return EOS_OK; +} + +static int ppp_disconnect(void) { + int rv; + + pppapi_close(ppp_handle, 0); + + rv = ppp_pause(1000, 2); + if (rv) return rv; + + at_cmd("ATH\r"); + at_expect("^OK", NULL, 1000); + + xSemaphoreGive(uart_mutex); + xSemaphoreGive(ppp_mutex); + ppp_handle = NULL; + + return EOS_OK; +} + +void eos_modem_init(void) { + /* Configure parameters of an UART driver, + * communication pins and install the driver */ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + }; + uart_param_config(UART_NUM_2, &uart_config); + uart_set_pin(UART_NUM_2, UART_GPIO_TXD, UART_GPIO_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + uart_driver_install(UART_NUM_2, UART_SIZE_IO_BUF, UART_SIZE_IO_BUF, 10, &uart_queue, 0); + + // Configuration for the DTR/RI lines + gpio_config_t io_conf; + + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pin_bit_mask = ((uint64_t)1 << UART_GPIO_DTR); + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + gpio_set_level(UART_GPIO_DTR, 0); + + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pin_bit_mask = ((uint64_t)1 << UART_GPIO_RI); + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); + + uart_mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(uart_mutex); + + ppp_mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(ppp_mutex); + + modem_queue = xQueueCreate(4, sizeof(modem_event_t)); + xTaskCreate(uart_event_task, "uart_event", EOS_TASK_SSIZE_UART, NULL, EOS_TASK_PRIORITY_UART, NULL); + xTaskCreate(modem_event_task, "modem_event", EOS_TASK_SSIZE_MODEM, NULL, EOS_TASK_PRIORITY_MODEM, NULL); + + gpio_isr_handler_add(UART_GPIO_RI, uart_ri_isr_handler, NULL); + + at_init(); + at_urc_insert("^PB DONE", modem_urc_init_handler, REG_EXTENDED); + eos_modem_set_mode(EOS_CELL_UART_MODE_ATCMD); + + ESP_LOGI(TAG, "INIT"); +} + +void eos_modem_flush(void){ + uart_wait_tx_done(UART_NUM_2, portMAX_DELAY); +} + +size_t eos_modem_write(void *data, size_t size) { + return uart_write_bytes(UART_NUM_2, (const char *)data, size); +} + +size_t eos_modem_read(void *data, size_t size, uint32_t timeout) { + return uart_read_bytes(UART_NUM_2, (uint8_t *)data, size, timeout / portTICK_RATE_MS); +} + +int eos_modem_readln(char *buf, size_t buf_size, uint32_t timeout) { + char *ln_end = NULL; + size_t buf_len = 0; + uint64_t t_start = esp_timer_get_time(); + + buf[0] = '\0'; + if (uart_buf_len) { + buf_len = MIN(buf_size -1, uart_buf_len); + memcpy(buf, uart_buf, buf_len); + buf[buf_len] = '\0'; + ln_end = strchr(buf, '\n'); + + uart_buf_len -= buf_len; + if (uart_buf_len) memmove(uart_buf, uart_buf + buf_len, uart_buf_len); + } + + while (ln_end == NULL) { + int len; + + if (buf_len == buf_size - 1) return EOS_ERR_FULL; + if (timeout && ((uint32_t)((esp_timer_get_time() - t_start) / 1000) > timeout)) return EOS_ERR_TIMEOUT; + + len = eos_modem_read(buf + buf_len, MIN(buf_size - buf_len - 1, sizeof(uart_buf) - uart_buf_len), 10); + if (len > 0) { + buf[buf_len + len] = '\0'; + ln_end = strchr(buf + buf_len, '\n'); + buf_len += len; + } + } + buf_len -= ln_end - buf + 1; + if (buf_len) { + if (uart_buf_len) memmove(uart_buf + buf_len, uart_buf, uart_buf_len); + memcpy(uart_buf, ln_end + 1, buf_len); + uart_buf_len += buf_len; + } + + if ((ln_end > buf) && (*(ln_end - 1) == '\r')) ln_end--; + *ln_end = '\0'; + + return EOS_OK; +} + +uint8_t eos_modem_get_mode(void) { + uint8_t ret; + + xSemaphoreTake(mutex, portMAX_DELAY); + ret = uart_mode; + xSemaphoreGive(mutex); + + return ret; +} + +int eos_modem_set_mode(uint8_t mode) { + int rv = EOS_OK; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (mode != uart_mode) { + if (uart_mode == EOS_CELL_UART_MODE_PPP) rv = ppp_disconnect(); + if (!rv) { + if (mode == EOS_CELL_UART_MODE_PPP) { + rv = ppp_setup(); + } else { + modem_set_mode(mode); + } + if (!rv) uart_mode = mode; + } + } + xSemaphoreGive(mutex); + + return rv; +} + +int eos_modem_take(uint32_t timeout) { + int rv = EOS_OK; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (uart_mode == EOS_CELL_UART_MODE_PPP) { + rv = ppp_pause(timeout, 0); + } else { + int r; + + modem_set_mode(EOS_CELL_UART_MODE_NONE); + r = xSemaphoreTake(uart_mutex, timeout ? timeout / portTICK_PERIOD_MS : portMAX_DELAY); + if (r == pdFALSE) { + modem_set_mode(uart_mode); + rv = EOS_ERR_TIMEOUT; + } + } + + if (rv) xSemaphoreGive(mutex); + + return rv; +} + +void eos_modem_give(void) { + if (uart_mode == EOS_CELL_UART_MODE_PPP) { + int rv = ppp_resume(); + if (rv) ESP_LOGW(TAG, "PPP resume failed"); + } else { + modem_set_mode(uart_mode); + xSemaphoreGive(uart_mutex); + } + xSemaphoreGive(mutex); +} + +void eos_modem_sleep(uint8_t mode) { + int r; + + xSemaphoreTake(mutex, portMAX_DELAY); + modem_set_mode(EOS_CELL_UART_MODE_NONE); + r = xSemaphoreTake(uart_mutex, 1000 / portTICK_PERIOD_MS); + if (r == pdFALSE) { + ESP_LOGE(TAG, "Obtaining mutex before sleep failed"); + } + gpio_set_level(UART_GPIO_DTR, 1); + if (mode == EOS_PWR_SMODE_DEEP) { + gpio_hold_en(UART_GPIO_DTR); + } +} + +void eos_modem_wake(uint8_t source, uint8_t mode) { + if (source == EOS_PWR_WAKE_UART) { + modem_event_t evt; + + evt.type = MODEM_ETYPE_RI; + xQueueSend(modem_queue, &evt, portMAX_DELAY); + } + + if (mode != EOS_PWR_SMODE_DEEP) { + gpio_set_intr_type(UART_GPIO_RI, GPIO_INTR_NEGEDGE); + gpio_isr_handler_add(UART_GPIO_RI, uart_ri_isr_handler, NULL); + gpio_set_level(UART_GPIO_DTR, 0); + + modem_set_mode(uart_mode); + xSemaphoreGive(uart_mutex); + xSemaphoreGive(mutex); + } else { + gpio_hold_dis(UART_GPIO_DTR); + } +} + +void eos_ppp_set_apn(char *apn) { + xSemaphoreTake(mutex, portMAX_DELAY); + strncpy(ppp_apn, apn, sizeof(ppp_apn) - 1); + xSemaphoreGive(mutex); +} + +void eos_ppp_set_auth(char *user, char *pass) { + xSemaphoreTake(mutex, portMAX_DELAY); + strncpy(ppp_user, user, sizeof(ppp_user) - 1); + strncpy(ppp_pass, pass, sizeof(ppp_pass) - 1); + xSemaphoreGive(mutex); +} + +int eos_ppp_connect(void) { + return eos_modem_set_mode(EOS_CELL_UART_MODE_PPP); +} + +int eos_ppp_disconnect(void) { + int rv = eos_modem_set_mode(EOS_CELL_UART_MODE_ATCMD); + + xSemaphoreTake(mutex, portMAX_DELAY); + memset(ppp_apn, 0, sizeof(ppp_apn)); + memset(ppp_user, 0, sizeof(ppp_user)); + memset(ppp_pass, 0, sizeof(ppp_pass)); + xSemaphoreGive(mutex); + + return rv; +}
\ No newline at end of file diff --git a/fw/esp32/components/eos/cell_pcm.c b/fw/esp32/components/eos/cell_pcm.c new file mode 100644 index 0000000..5c59643 --- /dev/null +++ b/fw/esp32/components/eos/cell_pcm.c @@ -0,0 +1,258 @@ +#include <stdlib.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/semphr.h> +#include <freertos/task.h> +#include <freertos/queue.h> +#include <driver/i2s.h> +#include <driver/gpio.h> +#include <esp_log.h> + +#include "eos.h" +#include "net.h" +#include "msgq.h" +#include "cell.h" + +#define PCM_MIC_WM 128 +#define PCM_HOLD_CNT_TX 3 +#define PCM_HOLD_CNT_RX 3 +#define PCM_SIZE_BUFQ 4 +#define PCM_SIZE_BUF (PCM_MIC_WM * 4) + +#define PCM_GPIO_BCK 33 +#define PCM_GPIO_WS 4 +#define PCM_GPIO_DIN 34 +#define PCM_GPIO_DOUT 2 + +#define PCM_ETYPE_WRITE 1 + +static EOSBufQ pcm_buf_q; +static unsigned char *pcm_bufq_array[PCM_SIZE_BUFQ]; + +static EOSMsgQ pcm_evt_q; +static EOSMsgItem pcm_evtq_array[PCM_SIZE_BUFQ]; +static char pcm_hold_tx; + +static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1}; + +static QueueHandle_t i2s_queue; +static SemaphoreHandle_t mutex; + +static const char *TAG = "EOS PCM"; + +static void i2s_event_task(void *pvParameters) { + i2s_event_t event; + unsigned char *buf; + unsigned char _type; + size_t bytes_w; + ssize_t bytes_r; + uint16_t bytes_e; + ssize_t hold_bytes_r = 0; + unsigned char *hold_buf = NULL; + char hold_cnt = 0; + + while (1) { + // Waiting for I2S event. + if (xQueueReceive(i2s_queue, &event, portMAX_DELAY)) { + switch (event.type) { + case I2S_EVENT_RX_DONE: + // Event of I2S receiving data + if (!hold_cnt) { + buf = eos_net_alloc(); + buf[0] = EOS_CELL_MTYPE_PCM_DATA; + bytes_r = eos_cell_pcm_read(buf + 1, PCM_MIC_WM); + eos_net_send(EOS_NET_MTYPE_CELL, buf, bytes_r + 1, 0); + } else { + hold_cnt--; + if (hold_buf == NULL) { + hold_buf = eos_net_alloc(); + hold_buf[0] = EOS_CELL_MTYPE_PCM_DATA; + } + if (1 + hold_bytes_r + PCM_MIC_WM <= EOS_NET_SIZE_BUF) hold_bytes_r += eos_cell_pcm_read(hold_buf + 1 + hold_bytes_r, PCM_MIC_WM); + if (hold_cnt == 0) { + eos_net_send(EOS_NET_MTYPE_CELL, hold_buf, hold_bytes_r + 1, 0); + hold_bytes_r = 0; + hold_buf = NULL; + } + } + + buf = NULL; + xSemaphoreTake(mutex, portMAX_DELAY); + if (pcm_hold_tx && (eos_msgq_len(&pcm_evt_q) == PCM_HOLD_CNT_TX)) pcm_hold_tx = 0; + if (!pcm_hold_tx) eos_msgq_pop(&pcm_evt_q, &_type, &buf, &bytes_e, NULL); + xSemaphoreGive(mutex); + + if (buf) { + i2s_write(I2S_NUM_0, (const void *)buf, bytes_e, &bytes_w, portMAX_DELAY); + xSemaphoreTake(mutex, portMAX_DELAY); + eos_bufq_push(&pcm_buf_q, buf); + xSemaphoreGive(mutex); + } + break; + case I2S_EVENT_DMA_ERROR: + ESP_LOGE(TAG, "*** I2S DMA ERROR ***"); + break; + case I2S_EVENT_MAX: + hold_cnt = PCM_HOLD_CNT_RX; + break; + default: + break; + } + } + } + vTaskDelete(NULL); +} + +void eos_cell_pcm_init(void) { + int i; + + i2s_config_t i2s_config = { + .mode = I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX, + .sample_rate = 32000, + .bits_per_sample = 32, + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S, + .dma_buf_count = 4, + .dma_buf_len = PCM_MIC_WM, + .use_apll = true, + .fixed_mclk = 2048000 * 8, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 + }; + + i2s_pin_config_t pin_config = { + .bck_io_num = PCM_GPIO_BCK, + .ws_io_num = PCM_GPIO_WS, + .data_in_num = PCM_GPIO_DIN, + .data_out_num = PCM_GPIO_DOUT + }; + i2s_driver_install(I2S_NUM_0, &i2s_config, 10, &i2s_queue); //install and start i2s driver + i2s_stop(I2S_NUM_0); + i2s_set_pin(I2S_NUM_0, &pin_config); + gpio_matrix_in(pin_config.ws_io_num, I2S0I_WS_IN_IDX, 1); + gpio_matrix_in(pin_config.bck_io_num, I2S0I_BCK_IN_IDX, 1); + ESP_LOGI(TAG, "TX FIFO:%d TX CHAN:%d RX FIFO:%d RX CHAN:%d", I2S[I2S_NUM_0]->fifo_conf.tx_fifo_mod, I2S[I2S_NUM_0]->conf_chan.tx_chan_mod, I2S[I2S_NUM_0]->fifo_conf.rx_fifo_mod, I2S[I2S_NUM_0]->conf_chan.rx_chan_mod); + + I2S[I2S_NUM_0]->fifo_conf.tx_fifo_mod = 2; + I2S[I2S_NUM_0]->conf_chan.tx_chan_mod = 0; + + I2S[I2S_NUM_0]->fifo_conf.rx_fifo_mod = 3; + I2S[I2S_NUM_0]->conf_chan.rx_chan_mod = 1; + // I2S[I2S_NUM_0]->conf.tx_mono = 1; + I2S[I2S_NUM_0]->conf.rx_mono = 1; + // I2S[I2S_NUM_0]->timing.tx_dsync_sw = 1 + // I2S[I2S_NUM_0]->timing.rx_dsync_sw = 1 + // I2S[I2S_NUM_0]->conf.sig_loopback = 0; + + // I2S[I2S_NUM_0]->timing.tx_bck_in_inv = 1; + + eos_msgq_init(&pcm_evt_q, pcm_evtq_array, PCM_SIZE_BUFQ); + eos_bufq_init(&pcm_buf_q, pcm_bufq_array, PCM_SIZE_BUFQ); + for (i=0; i<PCM_SIZE_BUFQ; i++) { + eos_bufq_push(&pcm_buf_q, malloc(PCM_SIZE_BUF)); + } + + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); + + // Create a task to handle i2s event from ISR + xTaskCreate(i2s_event_task, "i2s_event", EOS_TASK_SSIZE_I2S, NULL, EOS_TASK_PRIORITY_I2S, NULL); + ESP_LOGI(TAG, "INIT"); +} + +ssize_t eos_cell_pcm_read(unsigned char *data, size_t size) { + static unsigned char buf[PCM_SIZE_BUF]; + size_t bytes_r; + int i; + + if (size > PCM_MIC_WM) return EOS_ERR; + + esp_err_t ret = i2s_read(I2S_NUM_0, (void *)buf, size * 4, &bytes_r, portMAX_DELAY); + if (ret != ESP_OK) return EOS_ERR; + + for (i=0; i<size/2; i++) { + data[i * 2] = buf[i * 8 + 3]; + data[i * 2 + 1] = buf[i * 8 + 2]; + } + + return bytes_r / 4; +} + +static ssize_t pcm_expand(unsigned char *buf, unsigned char *data, size_t size) { + int i; + + if (size > PCM_MIC_WM) return EOS_ERR; + + memset(buf, 0, PCM_SIZE_BUF); + for (i=0; i<size/2; i++) { + buf[i * 8 + 3] = data[i * 2]; + buf[i * 8 + 2] = data[i * 2 + 1]; + } + + return size * 4; +} + +int eos_cell_pcm_push(unsigned char *data, size_t size) { + unsigned char *buf = NULL; + ssize_t esize; + int rv; + + if (size > PCM_MIC_WM) return EOS_ERR; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (pcm_hold_tx && (eos_msgq_len(&pcm_evt_q) == PCM_HOLD_CNT_TX)) { + unsigned char _type; + uint16_t _len; + + eos_msgq_pop(&pcm_evt_q, &_type, &buf, &_len, NULL); + } else { + buf = eos_bufq_pop(&pcm_buf_q); + } + xSemaphoreGive(mutex); + + if (buf == NULL) return EOS_ERR_EMPTY; + + esize = pcm_expand(buf, data, size); + if (esize < 0) { + xSemaphoreTake(mutex, portMAX_DELAY); + eos_bufq_push(&pcm_buf_q, buf); + xSemaphoreGive(mutex); + return esize; + } + + xSemaphoreTake(mutex, portMAX_DELAY); + rv = eos_msgq_push(&pcm_evt_q, PCM_ETYPE_WRITE, buf, esize, 0); + if (rv) eos_bufq_push(&pcm_buf_q, buf); + xSemaphoreGive(mutex); + + return rv; +} + +void eos_cell_pcm_start(void) { + i2s_event_t evt; + + xSemaphoreTake(mutex, portMAX_DELAY); + while (1) { + unsigned char _type; + unsigned char *buf; + uint16_t len; + + eos_msgq_pop(&pcm_evt_q, &_type, &buf, &len, NULL); + if (buf) { + eos_bufq_push(&pcm_buf_q, buf); + } else { + break; + } + } + pcm_hold_tx = 1; + xSemaphoreGive(mutex); + + evt.type = I2S_EVENT_MAX; /* my type */ + xQueueSend(i2s_queue, &evt, portMAX_DELAY); + i2s_zero_dma_buffer(I2S_NUM_0); + i2s_start(I2S_NUM_0); +} + +void eos_cell_pcm_stop(void) { + i2s_stop(I2S_NUM_0); +} diff --git a/fw/esp32/components/eos/cell_sms.c b/fw/esp32/components/eos/cell_sms.c new file mode 100644 index 0000000..05acc50 --- /dev/null +++ b/fw/esp32/components/eos/cell_sms.c @@ -0,0 +1,22 @@ +#include <stdlib.h> +#include <stdio.h> + +#include <esp_log.h> + +#include "eos.h" +#include "cell.h" + + +void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t size) { + int rv; + + rv = eos_modem_take(1000); + if (rv) return; + + buffer += 1; + size -= 1; + switch (mtype) { + } + + eos_modem_give(); +} diff --git a/fw/esp32/components/eos/cell_ussd.c b/fw/esp32/components/eos/cell_ussd.c new file mode 100644 index 0000000..2daa00f --- /dev/null +++ b/fw/esp32/components/eos/cell_ussd.c @@ -0,0 +1,34 @@ +#include <stdlib.h> +#include <stdio.h> + +#include <esp_log.h> + +#include "at_cmd.h" +#include "cell.h" +#include "gsm.h" + +static char cmd[256]; + +void eos_cell_ussd_handler(unsigned char mtype, unsigned char *buffer, uint16_t size) { + int cmd_len, rv; + + rv = eos_modem_take(1000); + if (rv) return; + + buffer += 1; + size -= 1; + switch (mtype) { + case EOS_CELL_MTYPE_USSD_REQUEST: + if (size == 0) return; + + buffer[size] = '\0'; + cmd_len = snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", buffer); + if ((cmd_len < 0) || (cmd_len >= sizeof(cmd))) return; + at_cmd(cmd); + + break; + } + + eos_modem_give(); +} + diff --git a/fw/esp32/components/eos/cell_voice.c b/fw/esp32/components/eos/cell_voice.c new file mode 100644 index 0000000..3f6a2a5 --- /dev/null +++ b/fw/esp32/components/eos/cell_voice.c @@ -0,0 +1,20 @@ +#include <stdlib.h> + +#include <esp_log.h> + +#include "eos.h" +#include "cell.h" + +void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t size) { + int rv; + + rv = eos_modem_take(1000); + if (rv) return; + + buffer += 1; + size -= 1; + switch (mtype) { + } + + eos_modem_give(); +} diff --git a/fw/esp32/components/eos/component.mk b/fw/esp32/components/eos/component.mk new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/fw/esp32/components/eos/component.mk diff --git a/fw/esp32/components/eos/drv2605l.c b/fw/esp32/components/eos/drv2605l.c new file mode 100644 index 0000000..3944289 --- /dev/null +++ b/fw/esp32/components/eos/drv2605l.c @@ -0,0 +1,82 @@ +#include <stdlib.h> + +#include <esp_log.h> + +#include "eos.h" +#include "i2c.h" + +static const char *TAG = "EOS DRV2605L"; + +#define DRV2605L_ADDR 0x5A + +#define DRV2605_REG_STATUS 0x00 ///< Status register +#define DRV2605_REG_MODE 0x01 ///< Mode register +#define DRV2605_MODE_INTTRIG 0x00 ///< Internal trigger mode +#define DRV2605_MODE_EXTTRIGEDGE 0x01 ///< External edge trigger mode +#define DRV2605_MODE_EXTTRIGLVL 0x02 ///< External level trigger mode +#define DRV2605_MODE_PWMANALOG 0x03 ///< PWM/Analog input mode +#define DRV2605_MODE_AUDIOVIBE 0x04 ///< Audio-to-vibe mode +#define DRV2605_MODE_REALTIME 0x05 ///< Real-time playback (RTP) mode +#define DRV2605_MODE_DIAGNOS 0x06 ///< Diagnostics mode +#define DRV2605_MODE_AUTOCAL 0x07 ///< Auto calibration mode + +#define DRV2605_REG_RTPIN 0x02 ///< Real-time playback input register +#define DRV2605_REG_LIBRARY 0x03 ///< Waveform library selection register +#define DRV2605_REG_WAVESEQ1 0x04 ///< Waveform sequence register 1 +#define DRV2605_REG_WAVESEQ2 0x05 ///< Waveform sequence register 2 +#define DRV2605_REG_WAVESEQ3 0x06 ///< Waveform sequence register 3 +#define DRV2605_REG_WAVESEQ4 0x07 ///< Waveform sequence register 4 +#define DRV2605_REG_WAVESEQ5 0x08 ///< Waveform sequence register 5 +#define DRV2605_REG_WAVESEQ6 0x09 ///< Waveform sequence register 6 +#define DRV2605_REG_WAVESEQ7 0x0A ///< Waveform sequence register 7 +#define DRV2605_REG_WAVESEQ8 0x0B ///< Waveform sequence register 8 + +#define DRV2605_REG_GO 0x0C ///< Go register +#define DRV2605_REG_OVERDRIVE 0x0D ///< Overdrive time offset register +#define DRV2605_REG_SUSTAINPOS 0x0E ///< Sustain time offset, positive register +#define DRV2605_REG_SUSTAINNEG 0x0F ///< Sustain time offset, negative register +#define DRV2605_REG_BREAK 0x10 ///< Brake time offset register +#define DRV2605_REG_AUDIOCTRL 0x11 ///< Audio-to-vibe control register +#define DRV2605_REG_AUDIOLVL 0x12 ///< Audio-to-vibe minimum input level register +#define DRV2605_REG_AUDIOMAX 0x13 ///< Audio-to-vibe maximum input level register +#define DRV2605_REG_AUDIOOUTMIN 0x14 ///< Audio-to-vibe minimum output drive register +#define DRV2605_REG_AUDIOOUTMAX 0x15 ///< Audio-to-vibe maximum output drive register +#define DRV2605_REG_RATEDV 0x16 ///< Rated voltage register +#define DRV2605_REG_CLAMPV 0x17 ///< Overdrive clamp voltage register +#define DRV2605_REG_AUTOCALCOMP 0x18 ///< Auto-calibration compensation result register +#define DRV2605_REG_AUTOCALEMP 0x19 ///< Auto-calibration back-EMF result register +#define DRV2605_REG_FEEDBACK 0x1A ///< Feedback control register +#define DRV2605_REG_CONTROL1 0x1B ///< Control1 Register +#define DRV2605_REG_CONTROL2 0x1C ///< Control2 Register +#define DRV2605_REG_CONTROL3 0x1D ///< Control3 Register +#define DRV2605_REG_CONTROL4 0x1E ///< Control4 Register +#define DRV2605_REG_VBAT 0x21 ///< Vbat voltage-monitor register +#define DRV2605_REG_LRARESON 0x22 ///< LRA resonance-period register + +void eos_drv2605l_test(void) { + uint8_t data = 0; + + int ret = eos_i2c_read(DRV2605L_ADDR, DRV2605_REG_STATUS, &data, 1); + if (ret) ESP_LOGE(TAG, "I2C ERROR!"); + + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_MODE, 0x00); // out of standby + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_RTPIN, 0x00); // no real-time-playback + + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_WAVESEQ1, 1); // strong click + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_WAVESEQ2, 0); // end sequence + + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_OVERDRIVE, 0); // no overdrive + + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_SUSTAINPOS, 0); + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_SUSTAINNEG, 0); + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_BREAK, 0); + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_AUDIOMAX, 0x64); + + // LRA open loop + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_FEEDBACK, eos_i2c_read8(DRV2605L_ADDR, DRV2605_REG_FEEDBACK) | 0x80); // turn on N_ERM_LRA + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_CONTROL3, eos_i2c_read8(DRV2605L_ADDR, DRV2605_REG_CONTROL3) | 0x01); // turn on LRA_OPEN_LOOP + + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_LIBRARY, 6); // set LRA library + eos_i2c_write8(DRV2605L_ADDR, DRV2605_REG_GO, 1); // go + +} diff --git a/fw/esp32/components/eos/gsm.c b/fw/esp32/components/eos/gsm.c new file mode 100644 index 0000000..788722e --- /dev/null +++ b/fw/esp32/components/eos/gsm.c @@ -0,0 +1,453 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "gsm.h" + +#define DIVC(x,y) ((x) / (y) + ((x) % (y) != 0)) + +uint8_t pdu_getc(char *pdu) { + int ch; + sscanf(pdu, "%2X", &ch); + return ch; +} + +void pdu_putc(uint8_t ch, char *pdu) { + sprintf(pdu, "%.2X", ch); +} + +void pdu_puts(uint8_t *s, int s_len, char *pdu) { + int i; + + for (i=0; i<s_len; i++) { + sprintf(pdu + 2 * i, "%.2X", s[i]); + } +} + +void pdu_gets(char *pdu, uint8_t *s, int s_len) { + int i, ch; + + for (i=0; i<s_len; i++) { + sscanf(pdu + 2 * i, "%2X", &ch); + s[i] = ch; + } +} + +void gsm_dcs_dec(uint8_t dcs, uint8_t *enc, uint16_t *flags) { + if ((dcs & GSM_DCS_GENERAL_IND) == 0) { + *enc = dcs & GSM_DCS_ENC; + if (dcs & GSM_DCS_CLASS_IND) { + *flags |= GSM_FLAG_CLASS; + *flags |= (uint16_t)(dcs & GSM_DCS_CLASS) << 8; + } + if (dcs & GSM_DCS_COMPRESS_IND) *flags |= GSM_FLAG_COMPRESS; + if (dcs & GSM_DCS_DELETE_IND) *flags |= GSM_FLAG_DELETE; + } else { + uint8_t group = dcs & GSM_DCS_GROUP; + + switch (group) { + case GSM_DCS_MWI_DISCARD: + case GSM_DCS_MWI_STORE_GSM7: + case GSM_DCS_MWI_STORE_UCS2: + if (group == GSM_DCS_MWI_STORE_UCS2) { + *enc = GSM_ENC_UCS2; + } else { + *enc = GSM_ENC_7BIT; + } + if (GSM_DCS_MWI_DISCARD) *flags |= GSM_FLAG_DISCARD; + *flags |= GSM_FLAG_MWI; + *flags |= (uint16_t)(dcs & (GSM_DCS_MWI_SENSE | GSM_DCS_MWI_TYPE)) << 12; + break; + + case GSM_DCS_ENCLASS: + *flags |= GSM_FLAG_CLASS; + *flags |= (uint16_t)(dcs & GSM_DCS_CLASS) << 8; + *enc = dcs & GSM_DCS_ENCLASS_ENC ? GSM_ENC_8BIT : GSM_ENC_7BIT; + break; + } + } +} + +void gsm_dcs_enc(uint8_t enc, uint16_t flags, uint8_t *dcs) { + *dcs = enc; + if (flags & GSM_FLAG_CLASS) { + *dcs |= GSM_DCS_CLASS_IND; + *dcs |= (flags >> 8) & GSM_DCS_CLASS; + } + if (flags & GSM_FLAG_COMPRESS) *dcs |= GSM_DCS_COMPRESS_IND; + if (flags & GSM_FLAG_DELETE) *dcs |= GSM_DCS_DELETE_IND; +} + +int gsm_ts_enc(char *ts, char *pdu, int pdu_size) { + uint8_t tz; + int tz_hh, tz_mm; + + if (pdu_size < 14) return GSM_ERR; + + pdu[1] = ts[2]; // YY + pdu[0] = ts[3]; + + pdu[3] = ts[5]; // MM + pdu[2] = ts[6]; + + pdu[5] = ts[8]; // DD + pdu[4] = ts[9]; + + pdu[7] = ts[11]; // hh + pdu[6] = ts[12]; + + pdu[9] = ts[14]; // mm + pdu[8] = ts[15]; + + pdu[11] = ts[17]; // ss + pdu[10] = ts[18]; + + sscanf(ts + 20, "%2d:%2d", &tz_hh, &tz_mm); + tz = tz_hh * 4 + tz_mm / 15; + tz = (tz / 10) | ((tz % 10) << 4); + if (ts[19] == '-') tz |= 0x08; + + pdu_putc(tz, pdu + 12); + + return 14; +} + +int gsm_ts_dec(char *pdu, int pdu_len, char *ts) { + uint8_t tz; + + if (pdu_len < 14) return GSM_ERR; + + ts[0] = '2'; + ts[1] = '0'; + ts[2] = pdu[1]; // YY + ts[3] = pdu[0]; + ts[4] = '-'; + ts[5] = pdu[3]; // MM + ts[6] = pdu[2]; + ts[7] = '-'; + ts[8] = pdu[5]; // DD + ts[9] = pdu[4]; + ts[10] = 'T'; + ts[11] = pdu[7]; // hh + ts[12] = pdu[6]; + ts[13] = ':'; + ts[14] = pdu[9]; // mm + ts[15] = pdu[8]; + ts[16] = ':'; + ts[17] = pdu[11]; // ss + ts[18] = pdu[10]; + + tz = pdu_getc(pdu + 12); + if (tz & 0x08) { + ts[19] = '-'; + tz = tz & ~0x08; + } else { + ts[19] = '+'; + } + tz = (tz & 0x0f) * 10 + (tz >> 4); + sprintf(ts + 20, "%.2d:%.2d", tz / 4, (tz % 4) * 15); + + return 14; +} + +int gsm_7bit_enc(char *text, int text_len, char *pdu, int padb) { + uint8_t carry = 0; + int i = 0, pdu_len = 0, shc = 0; + + if (!text_len) return 0; + + if (padb) { + shc = 7 - padb; + } else { + carry = *text; + i++; + } + + while (i < text_len) { + pdu_putc(carry | (*(text + i) << (7 - shc)), pdu + pdu_len); + pdu_len += 2; + + shc++; + shc = shc % 7; + if (!shc) { + i++; + if (i == text_len) return pdu_len; + } + + carry = *(text + i) >> shc; + i++; + } + pdu_putc(carry, pdu + pdu_len); + pdu_len += 2; + + return pdu_len; +} + +int gsm_7bit_dec(char *pdu, char *text, int text_len, int padb) { + uint8_t ch; + uint8_t carry = 0; + int i = 0, pdu_len = 0, shc = 0; + + if (!text_len) return 0; + + if (padb) { + ch = pdu_getc(pdu); + pdu_len += 2; + if (padb == 1) { + *text = ch >> 1; + i++; + } else { + carry = ch >> padb; + shc = 8 - padb; + } + } + + while (i < text_len) { + ch = pdu_getc(pdu + pdu_len); + pdu_len += 2; + + *(text + i) = ((ch << shc) | carry) & 0x7f; + carry = ch >> (7 - shc); + i++; + + shc++; + shc = shc % 7; + if (!shc && (i < text_len)) { + *(text + i) = carry; + carry = 0; + i++; + } + } + + return pdu_len; +} + +int gsm_addr_enc(char *addr, int addr_len, uint8_t addr_type, char *pdu, int pdu_size) { + int _pdu_len; + + addr_type |= GSM_EXT; + + if ((addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) { + int _addr_len = DIVC(addr_len * 7, 4); + + _pdu_len = 4 + DIVC(_addr_len, 2) * 2; + if (pdu_size < _pdu_len) return GSM_ERR; + + pdu_putc(_addr_len, pdu); + pdu_putc(addr_type, pdu + 2); + gsm_7bit_enc(addr, addr_len, pdu, 0); + } else { + int i; + + if (addr_type & GSM_TON_INTERNATIONAL) { + if (addr[0] != '+') return GSM_ERR; + addr++; + addr_len--; + } + _pdu_len = 4 + DIVC(addr_len, 2) * 2; + if (pdu_size < _pdu_len) return GSM_ERR; + + pdu_putc(addr_len, pdu); + pdu_putc(addr_type, pdu + 2); + for (i=0; i<addr_len / 2; i++) { + pdu[4 + 2 * i] = addr[2 * i + 1]; + pdu[4 + 2 * i + 1] = addr[2 * i]; + } + if (addr_len % 2 != 0) { + pdu[4 + 2 * i] = 'F'; + pdu[4 + 2 * i + 1] = addr[2 * i]; + } + } + + return _pdu_len; +} + +int gsm_addr_dec(char *pdu, int pdu_len, char *addr, int addr_size, int *addr_len, uint8_t *addr_type) { + int _pdu_len; + + if (pdu_len < 4) return GSM_ERR; + + *addr_len = pdu_getc(pdu); + *addr_type = pdu_getc(pdu + 2); + + if (!(*addr_type & GSM_EXT)) return GSM_ERR; + + _pdu_len = 4 + DIVC(*addr_len, 2) * 2; + if (pdu_len < _pdu_len) return GSM_ERR; + + if ((*addr_type & GSM_TON) == GSM_TON_ALPHANUMERIC) { + *addr_len = (*addr_len * 4) / 7; + if (addr_size < *addr_len) return GSM_ERR; + + gsm_7bit_dec(pdu + 4, addr, *addr_len, 0); + } else { + int i; + int _addr_len = *addr_len; + + if (*addr_type & GSM_TON_INTERNATIONAL) { + addr[0] = '+'; + addr++; + (*addr_len)++; + } + if (addr_size < *addr_len) return GSM_ERR; + + for (i=0; i<_addr_len / 2; i++) { + addr[2 * i] = pdu[4 + 2 * i + 1]; + addr[2 * i + 1] = pdu[4 + 2 * i]; + } + if (_addr_len % 2 != 0) { + addr[2 * i] = pdu[4 + 2 * i + 1]; + } + } + + return _pdu_len; +} + +int gsm_sms_enc(uint8_t pid, char *addr, int addr_len, uint8_t addr_type, uint8_t *udh, int udh_len, uint8_t *msg, int msg_len, uint8_t enc, uint16_t flags, char *pdu, int pdu_size) { + int rv, _pdu_len = 0; + uint8_t mti = GSM_MTI_SUBMIT; + uint8_t dcs = 0; + uint8_t udl; + + if (udh_len) mti |= GSM_UDHI; + + if (pdu_size < 4) return GSM_ERR; + pdu_putc(mti, pdu); + pdu_putc(00, pdu + 2); + _pdu_len += 4; + + rv = gsm_addr_enc(addr, addr_len, addr_type, pdu + _pdu_len, pdu_size - _pdu_len); + if (rv < 0) return rv; + _pdu_len += rv; + + if (pdu_size < _pdu_len + 4) return GSM_ERR; + gsm_dcs_enc(enc, flags, &dcs); + pdu_putc(pid, pdu + _pdu_len); + pdu_putc(dcs, pdu + _pdu_len + 2); + _pdu_len += 4; + + if (enc == GSM_ENC_7BIT) { + int udh_blen = 0; + int padb = 0; + + if (udh_len) { + udh_blen = 8 * (udh_len + 1); + padb = DIVC(udh_blen, 7) * 7 - udh_blen; + } + udl = DIVC(udh_blen, 7) + msg_len; + + if (pdu_size < _pdu_len + (DIVC(udl * 7, 8) + 1) * 2) return GSM_ERR; + pdu_putc(udl, pdu + _pdu_len); + _pdu_len += 2; + + if (udh_len) { + pdu_putc(udh_len, pdu + _pdu_len); + pdu_puts(udh, udh_len, pdu + _pdu_len + 2); + _pdu_len += (udh_len + 1) * 2; + } + + rv = gsm_7bit_enc((char *)msg, msg_len, pdu + _pdu_len, padb); + if (rv < 0) return rv; + _pdu_len += rv; + } else { + udl = msg_len + (udh_len ? udh_len + 1 : 0); + + if (pdu_size < _pdu_len + (udl + 1) * 2) return GSM_ERR; + pdu_putc(udl, pdu + _pdu_len); + _pdu_len += 2; + + if (udh_len) { + pdu_putc(udh_len, pdu + _pdu_len); + pdu_puts(udh, udh_len, pdu + _pdu_len + 2); + _pdu_len += (udh_len + 1) * 2; + } + + pdu_puts(msg, msg_len, pdu + _pdu_len); + _pdu_len += msg_len * 2; + } + + return _pdu_len; +} + +int gsm_sms_dec(char *pdu, int pdu_len, uint8_t *pid, char *addr, int addr_size, int *addr_len, uint8_t *addr_type, uint8_t *udh, int udh_size, int *udh_len, uint8_t *msg, int msg_size, int *msg_len, char *ts, uint8_t *enc, uint16_t *flags) { + int rv, _pdu_len = 0; + uint8_t mti; + uint8_t dcs; + uint8_t udl; + + if (pdu_len < 2) return GSM_ERR; + mti = pdu_getc(pdu); + _pdu_len += 2; + if ((mti & GSM_MTI) != GSM_MTI_DELIVER) return GSM_ERR; + + rv = gsm_addr_dec(pdu + _pdu_len, pdu_len - _pdu_len, addr, addr_size, addr_len, addr_type); + if (rv < 0) return rv; + _pdu_len += rv; + + if (pdu_len < _pdu_len + 4) return GSM_ERR; + *pid = pdu_getc(pdu + _pdu_len); + dcs = pdu_getc(pdu + _pdu_len + 2); + _pdu_len += 4; + gsm_dcs_dec(dcs, enc, flags); + + rv = gsm_ts_dec(pdu + _pdu_len, pdu_len - _pdu_len, ts); + if (rv < 0) return rv; + _pdu_len += rv; + + if (pdu_len < _pdu_len + 2) return GSM_ERR; + udl = pdu_getc(pdu + _pdu_len); + _pdu_len += 2; + + if ((mti & GSM_UDHI) && (udl == 0)) return GSM_ERR; + *udh_len = 0; + + if (*enc == GSM_ENC_7BIT) { + int udh_blen = 0; + int padb = 0; + + if (pdu_len < _pdu_len + DIVC(udl * 7, 8) * 2) return GSM_ERR; + + if (mti & GSM_UDHI) { + *udh_len = pdu_getc(pdu + _pdu_len); + udh_blen = 8 * (*udh_len + 1); + padb = DIVC(udh_blen, 7) * 7 - udh_blen; + + if (udl * 7 < udh_blen) return GSM_ERR; + if (udh_size < *udh_len) return GSM_ERR; + + pdu_gets(pdu + _pdu_len + 2, udh, *udh_len); + _pdu_len += (*udh_len + 1) * 2; + } else { + *udh_len = 0; + } + + *msg_len = udl - DIVC(udh_blen, 7); + if (msg_size < *msg_len) return GSM_ERR; + + rv = gsm_7bit_dec(pdu + _pdu_len, (char *)msg, *msg_len, padb); + if (rv < 0) return rv; + _pdu_len += rv; + } else { + if (pdu_len < _pdu_len + udl * 2) return GSM_ERR; + + if (mti & GSM_UDHI) { + *udh_len = pdu_getc(pdu + _pdu_len); + + if (udl < *udh_len + 1) return GSM_ERR; + if (udh_size < *udh_len) return GSM_ERR; + + pdu_gets(pdu + _pdu_len + 2, udh, *udh_len); + _pdu_len += (*udh_len + 1) * 2; + } else { + *udh_len = 0; + } + + *msg_len = udl - (*udh_len ? *udh_len + 1 : 0); + if (msg_size < *msg_len) return GSM_ERR; + + pdu_gets(pdu + _pdu_len, msg, *msg_len); + _pdu_len += *msg_len * 2; + } + + return _pdu_len; +} diff --git a/fw/esp32/components/eos/gsm_cp.c b/fw/esp32/components/eos/gsm_cp.c new file mode 100644 index 0000000..3ab98c5 --- /dev/null +++ b/fw/esp32/components/eos/gsm_cp.c @@ -0,0 +1,109 @@ +#include <stdint.h> + +#include "gsm.h" + +#define UCS2_SUPL_SIZE 11 + +static const uint16_t gsm7_to_ucs2[128] = { + 0x0040, 0x00a3, 0x0024, 0x00a5, 0x00e8, 0x00e9, 0x00f9, 0x00ec, 0x00f2, 0x00c7, 0x000a, 0x00d8, 0x00f8, 0x000d, 0x00c5, 0x00e5, + 0x0394, 0x005f, 0x03a6, 0x0393, 0x039b, 0x03a9, 0x03a0, 0x03a8, 0x03a3, 0x0398, 0x039e, 0x001b, 0x00c6, 0x00e6, 0x00df, 0x00c9, + 0x0020, 0x0021, 0x0022, 0x0023, 0x00a4, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x00a1, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00d1, 0x00dc, 0x00a7, + 0x00bf, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00f1, 0x00fc, 0x00e0 +}; + +static const uint16_t gsm7e_to_ucs2[128] = { + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x000c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0x005e, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x007b, 0x007d, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x005c, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x005b, 0x007e, 0x005d, 0xffff, + 0x007c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x20ac, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +static const uint16_t ucs2_to_gsm7[256] = { + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x000a, 0xffff, 0x1b0a, 0x000d, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x001b, 0xffff, 0xffff, 0xffff, 0xffff, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0002, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0000, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x1b3c, 0x1b2f, 0x1b3e, 0x1b14, 0x0011, + 0xffff, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x1b28, 0x1b40, 0x1b29, 0x1b3d, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0x0040, 0xffff, 0x0001, 0x0024, 0x0003, 0xffff, 0x005f, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0060, + 0xffff, 0xffff, 0xffff, 0xffff, 0x005b, 0x000e, 0x001c, 0x0009, 0xffff, 0x001f, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0x005d, 0xffff, 0xffff, 0xffff, 0xffff, 0x005c, 0xffff, 0x000b, 0xffff, 0xffff, 0xffff, 0x005e, 0xffff, 0xffff, 0x001e, + 0x007f, 0xffff, 0xffff, 0xffff, 0x007b, 0x000f, 0x001d, 0xffff, 0x0004, 0x0005, 0xffff, 0xffff, 0x0007, 0xffff, 0xffff, 0xffff, + 0xffff, 0x007d, 0x0008, 0xffff, 0xffff, 0xffff, 0x007c, 0xffff, 0x000c, 0x0006, 0xffff, 0xffff, 0x007e, 0xffff, 0xffff, 0xffff +}; + +static const uint16_t ucs2_to_gsm7_supl[UCS2_SUPL_SIZE][2] = { + {0x0394, 0x10}, + {0x03a6, 0x12}, + {0x0393, 0x13}, + {0x039b, 0x14}, + {0x03a9, 0x15}, + {0x03a0, 0x16}, + {0x03a8, 0x17}, + {0x03a3, 0x18}, + {0x0398, 0x19}, + {0x039e, 0x1a}, + {0x20ac, 0x1b65} +}; + +int gsm_ucs2_to_7bit(uint16_t ucs2, char *gsm7, int gsm7_size) { + uint16_t ch = 0xffff; + int ret = 0; + + if (gsm7_size < 1) return GSM_ERR; + + if (ucs2 < 256) { + ch = ucs2_to_gsm7[ucs2]; + } else { + int i; + + for (i=0; i<UCS2_SUPL_SIZE; i++) { + if (ucs2_to_gsm7_supl[i][0] == ucs2) { + ch = ucs2_to_gsm7_supl[i][1]; + break; + } + } + } + if (ch == 0xffff) return GSM_ERR; + if (ch & 0xff00) { + if (gsm7_size < 2) return GSM_ERR; + *gsm7 = 0x1b; + gsm7++; + ret++; + } + *gsm7 = ch & 0x7f; + ret++; + + return ret; +} + +int gsm_7bit_to_ucs2(char *gsm7, int gsm7_len, uint16_t *ucs2) { + int ret; + + if (gsm7_len < 1) return GSM_ERR; + if (*gsm7 != 0x1b) { + *ucs2 = gsm7_to_ucs2[*gsm7 & 0x7f]; + ret = 1; + } else { + if (gsm7_len < 2) return GSM_ERR; + gsm7++; + ret = 2; + *ucs2 = gsm7e_to_ucs2[*gsm7 & 0x7f]; + } + if (*ucs2 == 0xffff) return GSM_ERR; + + return ret; +} diff --git a/fw/esp32/components/eos/i2c.c b/fw/esp32/components/eos/i2c.c new file mode 100644 index 0000000..5b8fcc7 --- /dev/null +++ b/fw/esp32/components/eos/i2c.c @@ -0,0 +1,103 @@ +#include <stdlib.h> + +#include <esp_log.h> +#include <driver/i2c.h> + +#include "eos.h" + +static const char *TAG = "EOS I2C"; + +#define I2C_MASTER_NUM I2C_NUM_0 +#define I2C_MASTER_FREQ_HZ 100000 +#define I2C_MASTER_GPIO_SCL 25 +#define I2C_MASTER_GPIO_SDA 26 + +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NCK_VAL 0x1 /*!< I2C nack value */ + +/** + * @brief i2c initialization + */ + +void eos_i2c_init(void) { + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = I2C_MASTER_GPIO_SDA; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = I2C_MASTER_GPIO_SCL; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = I2C_MASTER_FREQ_HZ; + i2c_param_config(I2C_MASTER_NUM, &conf); + i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + ESP_LOGI(TAG, "INIT"); +} + +/** + * @brief i2c read + */ + +int eos_i2c_read(uint8_t addr, uint8_t reg, uint8_t *data, size_t len) { + int i, ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, addr << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, addr << 1 | I2C_MASTER_READ, ACK_CHECK_EN); + for (i=0; i < len - 1; i++) { + i2c_master_read_byte(cmd, data+i, ACK_VAL); + } + i2c_master_read_byte(cmd, data+i, NCK_VAL); + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret != ESP_OK) { + return EOS_ERR; + } + return EOS_OK; +} + +/** + * @brief i2c read8 + */ + +uint8_t eos_i2c_read8(uint8_t addr, uint8_t reg) { + uint8_t data; + eos_i2c_read(addr, reg, &data, 1); + return data; +} + +/** + * @brief i2c write + */ + +int eos_i2c_write(uint8_t addr, uint8_t reg, uint8_t *data, size_t len) { + int i, ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, addr << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); + for (i=0; i < len; i++) { + i2c_master_write_byte(cmd, *(data+i), ACK_CHECK_EN); + } + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret != ESP_OK) { + return EOS_ERR; + } + return EOS_OK; +} + +/** + * @brief i2c write8 + */ + +void eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t data) { + eos_i2c_write(addr, reg, &data, 1); +} + diff --git a/fw/esp32/components/eos/include/_net.h b/fw/esp32/components/eos/include/_net.h new file mode 100644 index 0000000..35b5308 --- /dev/null +++ b/fw/esp32/components/eos/include/_net.h @@ -0,0 +1 @@ +#include "net.h"
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/at_cmd.h b/fw/esp32/components/eos/include/at_cmd.h new file mode 100644 index 0000000..615a1c1 --- /dev/null +++ b/fw/esp32/components/eos/include/at_cmd.h @@ -0,0 +1,20 @@ +#include <sys/types.h> +#include <stdint.h> +#include <regex.h> + +#define AT_SIZE_NMATCH 4 +#define AT_SIZE_PATTERN 64 + +#define AT_SIZE_URC_LIST 16 + +#define AT_URC_OK 0 +#define AT_URC_MORE 1 + +typedef int (*at_urc_cb_t) (char *, regmatch_t[]); + +void at_init(void); +int at_urc_process(char *urc); +int at_urc_insert(char *pattern, at_urc_cb_t cb, int flags); +int at_urc_delete(char *pattern); +void at_cmd(char *cmd); +int at_expect(char *str_ok, char *str_err, uint32_t timeout); diff --git a/fw/esp32/components/eos/include/bq25895.h b/fw/esp32/components/eos/include/bq25895.h new file mode 100644 index 0000000..b5a7f92 --- /dev/null +++ b/fw/esp32/components/eos/include/bq25895.h @@ -0,0 +1,3 @@ +#include <stdint.h> + +void eos_bq25895_set_ilim(void);
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/cell.h b/fw/esp32/components/eos/include/cell.h new file mode 100644 index 0000000..3bf6b32 --- /dev/null +++ b/fw/esp32/components/eos/include/cell.h @@ -0,0 +1,68 @@ +#include <sys/types.h> +#include <stdint.h> + +#define EOS_CELL_MTYPE_DEV 0x00 +#define EOS_CELL_MTYPE_VOICE 0x10 +#define EOS_CELL_MTYPE_SMS 0x20 +#define EOS_CELL_MTYPE_CBS 0x30 +#define EOS_CELL_MTYPE_USSD 0x40 +#define EOS_CELL_MTYPE_DATA 0x70 + +#define EOS_CELL_MTYPE_MASK 0xf0 +#define EOS_CELL_MAX_MTYPE 8 + +#define EOS_CELL_MTYPE_READY 0 +#define EOS_CELL_MTYPE_UART_DATA 1 +#define EOS_CELL_MTYPE_UART_TAKE 2 +#define EOS_CELL_MTYPE_UART_GIVE 3 +#define EOS_CELL_MTYPE_PCM_DATA 4 +#define EOS_CELL_MTYPE_PCM_START 5 +#define EOS_CELL_MTYPE_PCM_STOP 6 + +#define EOS_CELL_MTYPE_VOICE_DIAL 1 +#define EOS_CELL_MTYPE_VOICE_RING 2 +#define EOS_CELL_MTYPE_VOICE_ANSWER 3 +#define EOS_CELL_MTYPE_VOICE_HANGUP 4 +#define EOS_CELL_MTYPE_VOICE_BEGIN 5 +#define EOS_CELL_MTYPE_VOICE_END 6 + +#define EOS_CELL_MTYPE_USSD_REQUEST 1 +#define EOS_CELL_MTYPE_USSD_REPLY 2 + +#define EOS_CELL_UART_MODE_NONE 0 +#define EOS_CELL_UART_MODE_ATCMD 1 +#define EOS_CELL_UART_MODE_PPP 2 +#define EOS_CELL_UART_MODE_RELAY 3 + +#define EOS_CELL_UART_SIZE_BUF 128 + +void eos_cell_init(void); + +void eos_modem_init(void); +void eos_modem_flush(void); +size_t eos_modem_write(void *data, size_t size); +size_t eos_modem_read(void *data, size_t size, uint32_t timeout); +int eos_modem_readln(char *buf, size_t buf_size, uint32_t timeout); +int eos_modem_resp(char *ok_str, char *err_str, uint32_t timeout); +uint8_t eos_modem_get_mode(void); +int eos_modem_set_mode(uint8_t mode); +int eos_modem_take(uint32_t timeout); +void eos_modem_give(void); +void eos_modem_sleep(uint8_t mode); +void eos_modem_wake(uint8_t source, uint8_t mode); + +void eos_ppp_set_apn(char *apn); +void eos_ppp_set_auth(char *user, char *pass); +int eos_ppp_connect(void); +int eos_ppp_disconnect(void); + +void eos_cell_pcm_init(void); +ssize_t eos_cell_pcm_read(unsigned char *data, size_t size); +int eos_cell_pcm_push(unsigned char *data, size_t size); +void eos_cell_pcm_start(void); +void eos_cell_pcm_stop(void); + +void eos_cell_voice_handler(unsigned char mtype, unsigned char *buffer, uint16_t size); +void eos_cell_sms_handler(unsigned char mtype, unsigned char *buffer, uint16_t size); +void eos_cell_ussd_handler(unsigned char mtype, unsigned char *buffer, uint16_t size); +void eos_cell_data_handler(unsigned char mtype, unsigned char *buffer, uint16_t size); diff --git a/fw/esp32/components/eos/include/drv2605l.h b/fw/esp32/components/eos/include/drv2605l.h new file mode 100644 index 0000000..de222e4 --- /dev/null +++ b/fw/esp32/components/eos/include/drv2605l.h @@ -0,0 +1,3 @@ +#include <stdint.h> + +void eos_drv2605l_test(void);
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/eos.h b/fw/esp32/components/eos/include/eos.h new file mode 100644 index 0000000..0e660fb --- /dev/null +++ b/fw/esp32/components/eos/include/eos.h @@ -0,0 +1,23 @@ +#define EOS_OK 0 +#define EOS_ERR -1 +#define EOS_ERR_TIMEOUT -2 +#define EOS_ERR_BUSY -3 + +#define EOS_ERR_FULL -10 +#define EOS_ERR_EMPTY -11 +#define EOS_ERR_NOTFOUND -12 + +#define EOS_TASK_PRIORITY_UART 1 +#define EOS_TASK_PRIORITY_MODEM 1 +#define EOS_TASK_PRIORITY_I2S 1 +#define EOS_TASK_PRIORITY_NET_XCHG 1 +#define EOS_TASK_PRIORITY_UDP_RCVR 1 +#define EOS_TASK_PRIORITY_PWR 1 + +#define EOS_TASK_SSIZE_UART 4096 +#define EOS_TASK_SSIZE_MODEM 4096 +#define EOS_TASK_SSIZE_I2S 4096 +#define EOS_TASK_SSIZE_NET_XCHG 8192 +#define EOS_TASK_SSIZE_UDP_RCVR 4096 +#define EOS_TASK_SSIZE_PWR 4096 + diff --git a/fw/esp32/components/eos/include/gsm.h b/fw/esp32/components/eos/include/gsm.h new file mode 100644 index 0000000..2c4f7b4 --- /dev/null +++ b/fw/esp32/components/eos/include/gsm.h @@ -0,0 +1,117 @@ +#define GSM_OK 0 +#define GSM_ERR -1 + +/* Message-Type-Indicator */ +#define GSM_MTI 0x03 +#define GSM_MTI_DELIVER 0x00 +#define GSM_MTI_DELIVER_REPORT 0x00 +#define GSM_MTI_SUBMIT 0x01 +#define GSM_MTI_SUBMIT_REPORT 0x01 +#define GSM_MTI_COMMAND 0x02 +#define GSM_MTI_COMMAND_REPORT 0x02 + +#define GSM_MMS 0x04 /* More-Messages-to-Send */ +#define GSM_RD 0x04 /* Reject-Duplicates */ +#define GSM_LP 0x08 /* Loop-Prevention */ + +/* Validity-Period-Format */ +#define GSM_VPF 0x18 +#define GSM_VPF_NONE 0x00 +#define GSM_VPF_ENHANCED 0x08 +#define GSM_VPF_RELATIVE 0x10 +#define GSM_VPF_ABSOLUTE 0x18 + +#define GSM_SRI 0x20 /* Status-Report-Indication */ +#define GSM_SRR 0x20 /* Status-Report-Request */ +#define GSM_SRQ 0x20 /* Status-Report-Qualifier */ +#define GSM_UDHI 0x40 /* User-Data-Header-Indicator */ +#define GSM_RP 0x80 /* Reply-Path */ + +/* Type-of-Number */ +#define GSM_TON 0x70 +#define GSM_TON_UNKNOWN 0x00 +#define GSM_TON_INTERNATIONAL 0x10 +#define GSM_TON_NATIONAL 0x20 +#define GSM_TON_NETWORK 0x30 +#define GSM_TON_SUBSCRIBER 0x40 +#define GSM_TON_ALPHANUMERIC 0x50 +#define GSM_TON_ABBRREVIATED 0x60 + +/* Numbering-Plan-Identification */ +#define GSM_NPI 0x0f +#define GSM_NPI_UNKNOWN 0x00 +#define GSM_NPI_TELEPHONE 0x01 +#define GSM_NPI_DATA 0x03 +#define GSM_NPI_TELEX 0x04 +#define GSM_NPI_SCS1 0x05 +#define GSM_NPI_SCS2 0x06 +#define GSM_NPI_NATIONAL 0x08 +#define GSM_NPI_PRIVATE 0x09 +#define GSM_NPI_ERMES 0x0a + +#define GSM_EXT 0x80 + +/* Protocol-Identifier */ +#define GSM_PID_DEFAULT 0 +#define GSM_PID_TYPE0 64 + +/* Data-Coding-Scheme */ +#define GSM_DCS_CLASS 0x03 +#define GSM_DCS_ENC 0x0c + +#define GSM_DCS_CLASS_IND 0x10 +#define GSM_DCS_COMPRESS_IND 0x20 +#define GSM_DCS_DELETE_IND 0x40 +#define GSM_DCS_GENERAL_IND 0x80 +#define GSM_DCS_GROUP 0xf0 + +#define GSM_DCS_MWI_DISCARD 0xc0 +#define GSM_DCS_MWI_STORE_GSM7 0xd0 +#define GSM_DCS_MWI_STORE_UCS2 0xe0 +#define GSM_DCS_MWI_SENSE 0x08 +#define GSM_DCS_MWI_TYPE 0x03 + +#define GSM_DCS_ENCLASS 0xf0 +#define GSM_DCS_ENCLASS_ENC 0x04 + +/* Parameter-Indicator */ +#define GSM_PI_PID 0x01 +#define GSM_PI_DCS 0x02 +#define GSM_PI_UD 0x04 +#define GSM_PI_EXT 0x08 + +/* character set */ +#define GSM_ENC_7BIT 0x00 +#define GSM_ENC_8BIT 0x04 +#define GSM_ENC_UCS2 0x08 + +/* message waiting indication */ +#define GSM_MWI_TYPE_VOICEMAIL 0x00 +#define GSM_MWI_TYPE_FAX 0x01 +#define GSM_MWI_TYPE_EMAIL 0x02 +#define GSM_MWI_TYPE_OTHER 0x03 + +/* flags */ +#define GSM_FLAG_COMPRESS 0x0001 +#define GSM_FLAG_DELETE 0x0002 +#define GSM_FLAG_DISCARD 0x0004 + +/* message class */ +#define GSM_FLAG_CLASS 0x0400 +#define GSM_FLAG_CLASS0 0x0000 /* Flash */ +#define GSM_FLAG_CLASS1 0x0100 /* ME-specific */ +#define GSM_FLAG_CLASS2 0x0200 /* (U)SIM-specific */ +#define GSM_FLAG_CLASS4 0x0300 /* TE-specific */ +#define GSM_FLAG_CLASS_MASK 0x0f00 + +/* message waiting indication */ +#define GSM_FLAG_MWI 0x4000 +#define GSM_FLAG_MWI_SENSE 0x8000 +#define GSM_FLAG_MWI_VOICEMAIL 0x0000 +#define GSM_FLAG_MWI_FAX 0x1000 +#define GSM_FLAG_MWI_EMAIL 0x2000 +#define GSM_FLAG_MWI_OTHER 0x3000 +#define GSM_FLAG_MWI_MASK 0xf000 + +int gsm_7bit_enc(char *text, int text_len, char *pdu, int padb); +int gsm_7bit_dec(char *pdu, char *text, int text_len, int padb); diff --git a/fw/esp32/components/eos/include/i2c.h b/fw/esp32/components/eos/include/i2c.h new file mode 100644 index 0000000..144f5e1 --- /dev/null +++ b/fw/esp32/components/eos/include/i2c.h @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <stdint.h> + +void eos_i2c_init(void); + +int eos_i2c_read(uint8_t addr, uint8_t reg, uint8_t *data, size_t len); +uint8_t eos_i2c_read8(uint8_t addr, uint8_t reg); +int eos_i2c_write(uint8_t addr, uint8_t reg, uint8_t *data, size_t len); +void eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/fw/esp32/components/eos/include/msgq.h b/fw/esp32/components/eos/include/msgq.h new file mode 100644 index 0000000..86bb067 --- /dev/null +++ b/fw/esp32/components/eos/include/msgq.h @@ -0,0 +1,32 @@ +#include <stdint.h> + +typedef struct EOSMsgItem { + unsigned char type; + unsigned char *buffer; + uint16_t len; + uint8_t flags; +} EOSMsgItem; + +typedef struct EOSMsgQ { + uint8_t idx_r; + uint8_t idx_w; + uint8_t size; + EOSMsgItem *array; +} EOSMsgQ; + +void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size); +int eos_msgq_push(EOSMsgQ *msgq, unsigned char type, unsigned char *buffer, uint16_t len, uint8_t flags); +void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *type, unsigned char **buffer, uint16_t *len, uint8_t *flags); +uint8_t eos_msgq_len(EOSMsgQ *msgq); + +typedef struct EOSBufQ { + uint8_t idx_r; + uint8_t idx_w; + uint8_t size; + unsigned char **array; +} EOSBufQ; + +void eos_bufq_init(EOSBufQ *bufq, unsigned char **array, uint8_t size); +int eos_bufq_push(EOSBufQ *bufq, unsigned char *buffer); +unsigned char *eos_bufq_pop(EOSBufQ *bufq); +uint8_t eos_bufq_len(EOSBufQ *bufq); diff --git a/fw/esp32/components/eos/include/net.h b/fw/esp32/components/eos/include/net.h new file mode 100644 index 0000000..54bad6d --- /dev/null +++ b/fw/esp32/components/eos/include/net.h @@ -0,0 +1,34 @@ +#include <stdint.h> + +/* common */ +#define EOS_NET_SIZE_BUF 1500 + +#define EOS_NET_MTYPE_SOCK 1 +#define EOS_NET_MTYPE_POWER 4 + +#define EOS_NET_MTYPE_WIFI 5 +#define EOS_NET_MTYPE_CELL 6 +#define EOS_NET_MTYPE_SIP 7 +#define EOS_NET_MTYPE_APP 8 + +#define EOS_NET_MAX_MTYPE 8 + +#define EOS_NET_MTYPE_FLAG_ONEW 0x80 + +/* esp32 specific */ +#define EOS_NET_SIZE_BUFQ 4 +#define EOS_NET_SIZE_SNDQ 4 + +#define EOS_NET_FLAG_BFREE 0x1 +#define EOS_NET_FLAG_BCOPY 0x2 + +typedef void (*eos_net_fptr_t) (unsigned char, unsigned char *, uint16_t); + +void eos_net_init(void); + +unsigned char *eos_net_alloc(void); +void eos_net_free(unsigned char *buf); +int eos_net_send(unsigned char mtype, unsigned char *buffer, uint16_t len, uint8_t flags); +void eos_net_set_handler(unsigned char mtype, eos_net_fptr_t handler); +void eos_net_sleep_done(uint8_t mode); +void eos_net_wake(uint8_t source, uint8_t mode); diff --git a/fw/esp32/components/eos/include/power.h b/fw/esp32/components/eos/include/power.h new file mode 100644 index 0000000..0a57b19 --- /dev/null +++ b/fw/esp32/components/eos/include/power.h @@ -0,0 +1,20 @@ +#include <stdint.h> + +#define EOS_PWR_MTYPE_BUTTON 0 + +#define EOS_PWR_WAKE_RST 0 +#define EOS_PWR_WAKE_BTN 1 +#define EOS_PWR_WAKE_NET 2 +#define EOS_PWR_WAKE_MSG 3 +#define EOS_PWR_WAKE_UART 4 + +#define EOS_PWR_SMODE_LIGHT 1 +#define EOS_PWR_SMODE_DEEP 2 + +void eos_power_init(void); + +void eos_power_wait4init(void); +uint8_t eos_power_wakeup_cause(void); +void eos_power_sleep(void); +void eos_power_wake(uint8_t source); +void eos_power_net_ready(void);
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/sock.h b/fw/esp32/components/eos/include/sock.h new file mode 100644 index 0000000..7e937cb --- /dev/null +++ b/fw/esp32/components/eos/include/sock.h @@ -0,0 +1,18 @@ +#include <stdint.h> + +#define EOS_SOCK_MTYPE_PKT 0 +#define EOS_SOCK_MTYPE_OPEN_DGRAM 1 +#define EOS_SOCK_MTYPE_CLOSE 127 + +#define EOS_SOCK_MAX_SOCK 2 + +#define EOS_SOCK_SIZE_UDP_HDR 8 + +#define EOS_IPv4_ADDR_SIZE 4 + +typedef struct EOSNetAddr { + unsigned char host[EOS_IPv4_ADDR_SIZE]; + uint16_t port; +} EOSNetAddr; + +void eos_sock_init(void);
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/unicode.h b/fw/esp32/components/eos/include/unicode.h new file mode 120000 index 0000000..e859a65 --- /dev/null +++ b/fw/esp32/components/eos/include/unicode.h @@ -0,0 +1 @@ +../../../../fe310/eos/unicode.h
\ No newline at end of file diff --git a/fw/esp32/components/eos/include/wifi.h b/fw/esp32/components/eos/include/wifi.h new file mode 100644 index 0000000..6009f7c --- /dev/null +++ b/fw/esp32/components/eos/include/wifi.h @@ -0,0 +1,12 @@ +#define EOS_WIFI_MTYPE_SCAN 0 +#define EOS_WIFI_MTYPE_CONNECT 1 +#define EOS_WIFI_MTYPE_DISCONNECT 2 + +#define EOS_WIFI_MAX_MTYPE 3 + +void eos_wifi_init(void); + +int eos_wifi_scan(void); +int eos_wifi_set_auth(char *ssid, char *pass); +int eos_wifi_connect(void); +int eos_wifi_disconnect(void); diff --git a/fw/esp32/components/eos/msgq.c b/fw/esp32/components/eos/msgq.c new file mode 100644 index 0000000..c704399 --- /dev/null +++ b/fw/esp32/components/eos/msgq.c @@ -0,0 +1,69 @@ +#include <stdlib.h> + +#include "eos.h" +#include "msgq.h" + +#define IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1)) + +void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size) { + msgq->idx_r = 0; + msgq->idx_w = 0; + msgq->size = size; + msgq->array = array; +} + +int eos_msgq_push(EOSMsgQ *msgq, unsigned char type, unsigned char *buffer, uint16_t len, uint8_t flags) { + if ((uint8_t)(msgq->idx_w - msgq->idx_r) == msgq->size) return EOS_ERR_FULL; + + uint8_t idx = IDX_MASK(msgq->idx_w, msgq->size); + msgq->array[idx].type = type; + msgq->array[idx].buffer = buffer; + msgq->array[idx].len = len; + msgq->array[idx].flags = flags; + msgq->idx_w++; + return EOS_OK; +} + +void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *type, unsigned char **buffer, uint16_t *len, uint8_t *flags) { + if (msgq->idx_r == msgq->idx_w) { + *type = 0; + *buffer = NULL; + *len = 0; + if (flags) *flags = 0; + } else { + uint8_t idx = IDX_MASK(msgq->idx_r, msgq->size); + *type = msgq->array[idx].type; + *buffer = msgq->array[idx].buffer; + *len = msgq->array[idx].len; + if (flags) *flags = msgq->array[idx].flags; + msgq->idx_r++; + } +} + +uint8_t eos_msgq_len(EOSMsgQ *msgq) { + return (uint8_t)(msgq->idx_w - msgq->idx_r); +} + +void eos_bufq_init(EOSBufQ *bufq, unsigned char **array, uint8_t size) { + bufq->idx_r = 0; + bufq->idx_w = 0; + bufq->size = size; + bufq->array = array; +} + +int eos_bufq_push(EOSBufQ *bufq, unsigned char *buffer) { + if ((uint8_t)(bufq->idx_w - bufq->idx_r) == bufq->size) return EOS_ERR_FULL; + + bufq->array[IDX_MASK(bufq->idx_w++, bufq->size)] = buffer; + return EOS_OK; +} + +unsigned char *eos_bufq_pop(EOSBufQ *bufq) { + if (bufq->idx_r == bufq->idx_w) return NULL; + + return bufq->array[IDX_MASK(bufq->idx_r++, bufq->size)]; +} + +uint8_t eos_bufq_len(EOSBufQ *bufq) { + return (uint8_t)(bufq->idx_w - bufq->idx_r); +} diff --git a/fw/esp32/components/eos/net.c b/fw/esp32/components/eos/net.c new file mode 100644 index 0000000..9a4a024 --- /dev/null +++ b/fw/esp32/components/eos/net.c @@ -0,0 +1,285 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/semphr.h> +#include <freertos/task.h> + +#include <esp_system.h> +#include <esp_log.h> +#include <esp_err.h> +#include <esp_heap_caps.h> +#include <driver/gpio.h> +#include <driver/spi_slave.h> + +#include "eos.h" +#include "msgq.h" +#include "power.h" +#include "net.h" + +#define SPI_GPIO_RTS 22 +#define SPI_GPIO_CTS 21 +#define SPI_GPIO_MOSI 23 +#define SPI_GPIO_MISO 19 +#define SPI_GPIO_SCLK 18 +#define SPI_GPIO_CS 5 + +#define SPI_SIZE_BUF (EOS_NET_SIZE_BUF + 8) + +static volatile char net_sleep = 0; + +static EOSBufQ net_buf_q; +static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ]; + +static EOSMsgQ net_send_q; +static EOSMsgItem net_sndq_array[EOS_NET_SIZE_SNDQ]; + +static SemaphoreHandle_t mutex; +static SemaphoreHandle_t semaph; +static TaskHandle_t net_xchg_task_handle; +static const char *TAG = "EOS NET"; + +static eos_net_fptr_t mtype_handler[EOS_NET_MAX_MTYPE]; + +static void bad_handler(unsigned char mtype, unsigned char *buffer, uint16_t len) { + ESP_LOGE(TAG, "bad handler: %d len: %d", mtype, len); +} + +// Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high. +static void _post_setup_cb(spi_slave_transaction_t *trans) { + gpio_set_level(SPI_GPIO_CTS, 1); +} + +// Called after transaction is sent/received. We use this to set the handshake line low. +static void _post_trans_cb(spi_slave_transaction_t *trans) { + gpio_set_level(SPI_GPIO_CTS, 0); +} + +static void net_xchg_task(void *pvParameters) { + int repeat = 0; + int wake = 0; + unsigned char mtype = 0; + unsigned char *buffer; + uint16_t len; + uint8_t flags; + unsigned char *buf_send = heap_caps_malloc(SPI_SIZE_BUF, MALLOC_CAP_DMA); + unsigned char *buf_recv = heap_caps_malloc(SPI_SIZE_BUF, MALLOC_CAP_DMA); + esp_err_t ret; + spi_slave_transaction_t spi_tr; + + //Configuration for the SPI bus + spi_bus_config_t spi_bus_cfg = { + .mosi_io_num = SPI_GPIO_MOSI, + .miso_io_num = SPI_GPIO_MISO, + .sclk_io_num = SPI_GPIO_SCLK + }; + + //Configuration for the SPI slave interface + spi_slave_interface_config_t spi_slave_cfg = { + .mode = 0, + .spics_io_num = SPI_GPIO_CS, + .queue_size = 2, + .flags = 0, + .post_setup_cb = _post_setup_cb, + .post_trans_cb = _post_trans_cb + }; + + //Initialize SPI slave interface + ret = spi_slave_initialize(VSPI_HOST, &spi_bus_cfg, &spi_slave_cfg, 1); + assert(ret == ESP_OK); + + memset(&spi_tr, 0, sizeof(spi_tr)); + spi_tr.length = SPI_SIZE_BUF * 8; + spi_tr.tx_buffer = buf_send; + spi_tr.rx_buffer = buf_recv; + + if (eos_power_wakeup_cause()) { + wake = 1; + repeat = 1; + } + + eos_power_wait4init(); + while (1) { + if (!repeat) { + xSemaphoreTake(mutex, portMAX_DELAY); + + eos_msgq_pop(&net_send_q, &mtype, &buffer, &len, &flags); + if (mtype) { + buf_send[0] = mtype; + buf_send[1] = len >> 8; + buf_send[2] = len & 0xFF; + if (buffer) { + memcpy(buf_send + 3, buffer, len); + if (flags & EOS_NET_FLAG_BFREE) { + free(buffer); + } else { + eos_bufq_push(&net_buf_q, buffer); + xSemaphoreGive(semaph); + } + } + } else { + gpio_set_level(SPI_GPIO_RTS, 0); + buf_send[0] = 0; + buf_send[1] = 0; + buf_send[2] = 0; + } + + xSemaphoreGive(mutex); + } + repeat = 0; + + buf_recv[0] = 0; + buf_recv[1] = 0; + buf_recv[2] = 0; + spi_slave_transmit(VSPI_HOST, &spi_tr, portMAX_DELAY); + ESP_LOGD(TAG, "RECV:%d", buf_recv[0]); + + if (wake) { + eos_power_net_ready(); + wake = 0; + } + if (buf_recv[0] == 0x00) continue; + if (buf_recv[0] == 0xFF) { // Sleep req + if (buf_send[0] == 0) { + int abort = 0; + + xSemaphoreTake(mutex, portMAX_DELAY); + net_sleep = 1; + if (eos_msgq_len(&net_send_q)) abort = 1; + xSemaphoreGive(mutex); + + spi_slave_free(VSPI_HOST); + + eos_power_sleep(); + if (abort) eos_power_wake(EOS_PWR_WAKE_MSG); + + vTaskSuspend(NULL); + + xSemaphoreTake(mutex, portMAX_DELAY); + net_sleep = 0; + xSemaphoreGive(mutex); + + spi_slave_initialize(VSPI_HOST, &spi_bus_cfg, &spi_slave_cfg, 1); + wake = 1; + repeat = 1; + } + continue; + } + mtype = buf_recv[0]; + len = (uint16_t)buf_recv[1] << 8; + len |= (uint16_t)buf_recv[2] & 0xFF; + buffer = buf_recv + 3; + if (mtype & EOS_NET_MTYPE_FLAG_ONEW) { + mtype &= ~EOS_NET_MTYPE_FLAG_ONEW; + if (buf_send[0]) repeat = 1; + } + if (mtype <= EOS_NET_MAX_MTYPE) { + mtype_handler[mtype-1](mtype, buffer, len); + } else { + bad_handler(mtype, buffer, len); + } + } + vTaskDelete(NULL); +} + +void eos_net_init(void) { + int i; + + // Configuration for the handshake lines + gpio_config_t io_conf; + + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + io_conf.pin_bit_mask = ((uint64_t)1 << SPI_GPIO_CTS); + gpio_config(&io_conf); + gpio_set_level(SPI_GPIO_CTS, 0); + + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + io_conf.pin_bit_mask = ((uint64_t)1 << SPI_GPIO_RTS); + gpio_config(&io_conf); + gpio_set_level(SPI_GPIO_RTS, 0); + + eos_msgq_init(&net_send_q, net_sndq_array, EOS_NET_SIZE_SNDQ); + eos_bufq_init(&net_buf_q, net_bufq_array, EOS_NET_SIZE_BUFQ); + for (i=0; i<EOS_NET_SIZE_BUFQ; i++) { + eos_bufq_push(&net_buf_q, malloc(EOS_NET_SIZE_BUF)); + } + + for (i=0; i<EOS_NET_MAX_MTYPE; i++) { + mtype_handler[i] = bad_handler; + } + + semaph = xSemaphoreCreateCounting(EOS_NET_SIZE_BUFQ, EOS_NET_SIZE_BUFQ); + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); + xTaskCreate(&net_xchg_task, "net_xchg", EOS_TASK_SSIZE_NET_XCHG, NULL, EOS_TASK_PRIORITY_NET_XCHG, &net_xchg_task_handle); + ESP_LOGI(TAG, "INIT"); +} + +unsigned char *eos_net_alloc(void) { + unsigned char *ret; + + xSemaphoreTake(semaph, portMAX_DELAY); + xSemaphoreTake(mutex, portMAX_DELAY); + ret = eos_bufq_pop(&net_buf_q); + xSemaphoreGive(mutex); + + return ret; +} + +void eos_net_free(unsigned char *buf) { + xSemaphoreTake(mutex, portMAX_DELAY); + eos_bufq_push(&net_buf_q, buf); + xSemaphoreGive(semaph); + xSemaphoreGive(mutex); +} + +int eos_net_send(unsigned char mtype, unsigned char *buffer, uint16_t len, uint8_t flags) { + int rv, sleep; + + if (flags & EOS_NET_FLAG_BCOPY) xSemaphoreTake(semaph, portMAX_DELAY); + xSemaphoreTake(mutex, portMAX_DELAY); + sleep = net_sleep; + gpio_set_level(SPI_GPIO_RTS, 1); + if (flags & EOS_NET_FLAG_BCOPY) { + unsigned char *b = eos_bufq_pop(&net_buf_q); + memcpy(b, buffer, len); + buffer = b; + } + rv = eos_msgq_push(&net_send_q, mtype, buffer, len, flags); + xSemaphoreGive(mutex); + + if (sleep) eos_power_wake(EOS_PWR_WAKE_MSG); + + return rv; +} + +void eos_net_set_handler(unsigned char mtype, eos_net_fptr_t handler) { + mtype_handler[mtype-1] = handler; +} + +void eos_net_sleep_done(uint8_t mode) { + gpio_set_level(SPI_GPIO_CTS, 1); + vTaskDelay(200 / portTICK_PERIOD_MS); + gpio_set_level(SPI_GPIO_CTS, 0); +} + +void eos_net_wake(uint8_t source, uint8_t mode) { + int sleep; + + if (mode == EOS_PWR_SMODE_DEEP) return; + do { + vTaskResume(net_xchg_task_handle); + vTaskDelay(10 / portTICK_PERIOD_MS); + + xSemaphoreTake(mutex, portMAX_DELAY); + sleep = net_sleep; + xSemaphoreGive(mutex); + } while (sleep); +} diff --git a/fw/esp32/components/eos/power.c b/fw/esp32/components/eos/power.c new file mode 100644 index 0000000..f07e67b --- /dev/null +++ b/fw/esp32/components/eos/power.c @@ -0,0 +1,325 @@ +#include <stdlib.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/task.h> +#include <freertos/queue.h> +#include <driver/gpio.h> +#include <esp_sleep.h> +#include <esp_pm.h> +#include <esp_log.h> + +#include "eos.h" +#include "net.h" +#include "cell.h" +#include "power.h" + +#define POWER_GPIO_BTN 0 +#define POWER_GPIO_NET 5 +#define POWER_GPIO_UART 35 + +#define POWER_ETYPE_BTN 1 +#define POWER_ETYPE_SLEEP 2 +#define POWER_ETYPE_WAKE 3 +#define POWER_ETYPE_NETRDY 4 + +typedef struct { + uint8_t type; + union { + uint8_t source; + uint8_t level; + }; +} power_event_t; + +static esp_pm_lock_handle_t power_lock_cpu_freq; +static esp_pm_lock_handle_t power_lock_apb_freq; +static esp_pm_lock_handle_t power_lock_no_sleep; + +static const char *TAG = "EOS POWER"; + +static QueueHandle_t power_queue; + +static volatile int init_done = 0; + +static void IRAM_ATTR btn_handler(void *arg) { + power_event_t evt; + + evt.type = POWER_ETYPE_BTN; + evt.level = gpio_get_level(POWER_GPIO_BTN); + xQueueSendFromISR(power_queue, &evt, NULL); +} + +static void IRAM_ATTR btn_wake_handler(void *arg) { + power_event_t evt; + + gpio_intr_disable(POWER_GPIO_BTN); + + evt.type = POWER_ETYPE_WAKE; + evt.source = EOS_PWR_WAKE_BTN; + xQueueSendFromISR(power_queue, &evt, NULL); + +} + +static void IRAM_ATTR net_wake_handler(void *arg) { + power_event_t evt; + + gpio_intr_disable(POWER_GPIO_NET); + + evt.type = POWER_ETYPE_WAKE; + evt.source = EOS_PWR_WAKE_NET; + xQueueSendFromISR(power_queue, &evt, NULL); +} + +static void IRAM_ATTR uart_wake_handler(void *arg) { + power_event_t evt; + + gpio_intr_disable(POWER_GPIO_UART); + + evt.type = POWER_ETYPE_WAKE; + evt.source = EOS_PWR_WAKE_UART; + xQueueSendFromISR(power_queue, &evt, NULL); +} + +void power_sleep(uint8_t mode) { + gpio_config_t io_conf; + + eos_modem_sleep(mode); + eos_net_sleep_done(mode); + + switch (mode) { + case EOS_PWR_SMODE_LIGHT: + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_NET); + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + + gpio_isr_handler_add(POWER_GPIO_BTN, btn_wake_handler, NULL); + gpio_isr_handler_add(POWER_GPIO_NET, net_wake_handler, NULL); + gpio_isr_handler_add(POWER_GPIO_UART, uart_wake_handler, NULL); + + esp_sleep_enable_gpio_wakeup(); + gpio_wakeup_enable(POWER_GPIO_BTN, GPIO_INTR_LOW_LEVEL); + gpio_wakeup_enable(POWER_GPIO_NET, GPIO_INTR_LOW_LEVEL); + gpio_wakeup_enable(POWER_GPIO_UART, GPIO_INTR_LOW_LEVEL); + + ESP_LOGD(TAG, "SLEEP"); + + esp_pm_lock_release(power_lock_apb_freq); + esp_pm_lock_release(power_lock_no_sleep); + + break; + + case EOS_PWR_SMODE_DEEP: + gpio_deep_sleep_hold_en(); + esp_sleep_enable_ext0_wakeup(POWER_GPIO_BTN, 0); + esp_sleep_enable_ext1_wakeup((uint64_t)1 << POWER_GPIO_UART, ESP_EXT1_WAKEUP_ALL_LOW); + + ESP_LOGD(TAG, "SLEEP"); + + esp_deep_sleep_start(); + break; + + default: + break; + } +} + +void power_wake_stage1(uint8_t source, uint8_t mode) { + gpio_config_t io_conf; + + if (mode == EOS_PWR_SMODE_LIGHT) { + esp_pm_lock_acquire(power_lock_apb_freq); + esp_pm_lock_acquire(power_lock_no_sleep); + + gpio_wakeup_disable(POWER_GPIO_BTN); + gpio_wakeup_disable(POWER_GPIO_NET); + gpio_wakeup_disable(POWER_GPIO_UART); + + gpio_isr_handler_remove(POWER_GPIO_NET); + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_DISABLE; + io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_NET); + io_conf.pull_up_en = 0; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + } + + gpio_intr_disable(POWER_GPIO_BTN); + if ((source != EOS_PWR_WAKE_BTN) && (source != EOS_PWR_WAKE_NET)) { + gpio_set_direction(POWER_GPIO_BTN, GPIO_MODE_OUTPUT); + gpio_set_level(POWER_GPIO_BTN, 0); + vTaskDelay(200 / portTICK_PERIOD_MS); + gpio_set_direction(POWER_GPIO_BTN, GPIO_MODE_INPUT); + } + + eos_net_wake(source, mode); +} + +void power_wake_stage2(uint8_t source, uint8_t mode) { + eos_modem_wake(source, mode); + + gpio_set_intr_type(POWER_GPIO_BTN, GPIO_INTR_ANYEDGE); + gpio_isr_handler_add(POWER_GPIO_BTN, btn_handler, NULL); + + ESP_LOGD(TAG, "WAKE"); +} + +static void power_event_task(void *pvParameters) { + unsigned char *buf; + power_event_t evt; + uint8_t source; + uint8_t wakeup_cause; + uint8_t mode; + int sleep; + + source = 0; + wakeup_cause = eos_power_wakeup_cause(); + if (wakeup_cause) { + mode = EOS_PWR_SMODE_DEEP; + sleep = 1; + } else { + mode = EOS_PWR_SMODE_LIGHT; + sleep = 0; + } + + while (1) { + if (xQueueReceive(power_queue, &evt, portMAX_DELAY)) { + switch (evt.type) { + case POWER_ETYPE_SLEEP: + if (!sleep) { + mode = EOS_PWR_SMODE_DEEP; + power_sleep(mode); + sleep = 1; + } + break; + + case POWER_ETYPE_WAKE: + if (sleep) { + source = evt.source; + power_wake_stage1(source, mode); + } + break; + + case POWER_ETYPE_NETRDY: + if (sleep && source) { + power_wake_stage2(source, mode); + sleep = 0; + source = 0; + } + break; + + case POWER_ETYPE_BTN: + buf = eos_net_alloc(); + buf[0] = EOS_PWR_MTYPE_BUTTON; + buf[1] = evt.level; + eos_net_send(EOS_NET_MTYPE_POWER, buf, 2, 0); + break; + + default: + break; + } + } + } + vTaskDelete(NULL); +} + +void eos_power_init(void) { + esp_err_t ret; + gpio_config_t io_conf; + esp_pm_config_esp32_t pwr_conf; + uint8_t wakeup_cause; + + io_conf.intr_type = GPIO_INTR_ANYEDGE; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_BTN); + io_conf.pull_up_en = 1; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); + gpio_isr_handler_add(POWER_GPIO_BTN, btn_handler, NULL); + + /* + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + assert(ret == ESP_OK); + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON); + assert(ret == ESP_OK); + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); + assert(ret == ESP_OK); + */ + + ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, NULL, &power_lock_cpu_freq); + assert(ret == ESP_OK); + ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, NULL, &power_lock_apb_freq); + assert(ret == ESP_OK); + ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, NULL, &power_lock_no_sleep); + assert(ret == ESP_OK); + + ret = esp_pm_lock_acquire(power_lock_cpu_freq); + assert(ret == ESP_OK); + ret = esp_pm_lock_acquire(power_lock_apb_freq); + assert(ret == ESP_OK); + ret = esp_pm_lock_acquire(power_lock_no_sleep); + assert(ret == ESP_OK); + + pwr_conf.max_freq_mhz = 160; + pwr_conf.min_freq_mhz = 80; + pwr_conf.light_sleep_enable = 1; + + ret = esp_pm_configure(&pwr_conf); + assert(ret == ESP_OK); + + power_queue = xQueueCreate(4, sizeof(power_event_t)); + xTaskCreate(power_event_task, "power_event", EOS_TASK_SSIZE_PWR, NULL, EOS_TASK_PRIORITY_PWR, NULL); + + wakeup_cause = eos_power_wakeup_cause(); + if (wakeup_cause) eos_power_wake(wakeup_cause); + + init_done = 1; + ESP_LOGI(TAG, "INIT"); +} + +void eos_power_wait4init(void) { + while (!init_done); +} + +uint8_t eos_power_wakeup_cause(void) { + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + + switch (cause) { + case ESP_SLEEP_WAKEUP_EXT0: + return EOS_PWR_WAKE_BTN; + + case ESP_SLEEP_WAKEUP_EXT1: + return EOS_PWR_WAKE_UART; + + default: + case ESP_SLEEP_WAKEUP_UNDEFINED: + return EOS_PWR_WAKE_RST; + } +} + +void eos_power_sleep(void) { + power_event_t evt; + + evt.type = POWER_ETYPE_SLEEP; + evt.source = 0; + xQueueSend(power_queue, &evt, portMAX_DELAY); +} + +void eos_power_wake(uint8_t source) { + power_event_t evt; + + evt.type = POWER_ETYPE_WAKE; + evt.source = source; + + xQueueSend(power_queue, &evt, portMAX_DELAY); +} + +void eos_power_net_ready(void) { + power_event_t evt; + + evt.type = POWER_ETYPE_NETRDY; + evt.source = 0; + + xQueueSend(power_queue, &evt, portMAX_DELAY); +} diff --git a/fw/esp32/components/eos/sock.c b/fw/esp32/components/eos/sock.c new file mode 100644 index 0000000..17357e4 --- /dev/null +++ b/fw/esp32/components/eos/sock.c @@ -0,0 +1,163 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/semphr.h> +#include <freertos/task.h> + +#include <esp_system.h> +#include <esp_event.h> +#include <esp_event_loop.h> +#include <esp_log.h> +#include <esp_err.h> +#include <esp_wifi.h> +#include <nvs_flash.h> + +#include <lwip/sockets.h> +#include <lwip/err.h> +#include <lwip/sockets.h> +#include <lwip/sys.h> +#include <lwip/netdb.h> +#include <lwip/dns.h> + +#include "eos.h" +#include "net.h" +#include "sock.h" + +static const char *TAG = "EOS SOCK"; +static SemaphoreHandle_t mutex; +static int _socks[EOS_SOCK_MAX_SOCK]; + +static int t_open_dgram(void) { + struct sockaddr_in _myaddr; + int sock; + + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) return sock; + + memset((char *)&_myaddr, 0, sizeof(_myaddr)); + _myaddr.sin_family = AF_INET; + _myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + _myaddr.sin_port = htons(3000); + + int rv = bind(sock, (struct sockaddr *)&_myaddr, sizeof(_myaddr)); + if (rv < 0) { + close(sock); + return rv; + } + return sock; +} + +static void t_close(int sock) { + close(sock); +} + +static ssize_t t_sendto(int sock, void *msg, size_t msg_size, EOSNetAddr *addr) { + struct sockaddr_in servaddr; + + memset((void *)&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = addr->port; + memcpy((void *)&servaddr.sin_addr, addr->host, sizeof(addr->host)); + return sendto(sock, msg, msg_size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); +} + +static ssize_t t_recvfrom(int sock, void *msg, size_t msg_size, EOSNetAddr *addr) { + struct sockaddr_in servaddr; + socklen_t addrlen = sizeof(servaddr); + memset((void *)&servaddr, 0, sizeof(servaddr)); + + ssize_t recvlen = recvfrom(sock, msg, msg_size, 0, (struct sockaddr *)&servaddr, &addrlen); + if (recvlen < 0) return recvlen; + + if (addr) { + addr->port = servaddr.sin_port; + memcpy(addr->host, (void *)&servaddr.sin_addr, sizeof(addr->host)); + } + return recvlen; +} + +static void udp_rcvr_task(void *pvParameters) { + EOSNetAddr addr; + uint8_t esock = (uint8_t)pvParameters; + int sock = _socks[esock-1]; + unsigned char *buf; + + do { + ssize_t rv; + + buf = eos_net_alloc(); + rv = t_recvfrom(sock, buf+EOS_SOCK_SIZE_UDP_HDR, EOS_NET_SIZE_BUF-EOS_SOCK_SIZE_UDP_HDR, &addr); + if (rv < 0) { + sock = 0; + ESP_LOGE(TAG, "UDP RECV ERR:%d", rv); + continue; + } + buf[0] = EOS_SOCK_MTYPE_PKT; + buf[1] = esock; + memcpy(buf+2, addr.host, sizeof(addr.host)); + memcpy(buf+2+sizeof(addr.host), &addr.port, sizeof(addr.port)); + eos_net_send(EOS_NET_MTYPE_SOCK, buf, rv+EOS_SOCK_SIZE_UDP_HDR, 0); + } while(sock); + xSemaphoreTake(mutex, portMAX_DELAY); + _socks[esock-1] = 0; + xSemaphoreGive(mutex); + vTaskDelete(NULL); +} + +static void sock_handler(unsigned char type, unsigned char *buffer, uint16_t size) { + EOSNetAddr addr; + uint8_t esock; + int sock, i; + unsigned char *rbuf; + + if (size < 1) return; + + switch(buffer[0]) { + case EOS_SOCK_MTYPE_PKT: + if (size < EOS_SOCK_SIZE_UDP_HDR) return; + sock = _socks[buffer[1]-1]; + memcpy(addr.host, buffer+2, sizeof(addr.host)); + memcpy(&addr.port, buffer+2+sizeof(addr.host), sizeof(addr.port)); + t_sendto(sock, buffer+EOS_SOCK_SIZE_UDP_HDR, size-EOS_SOCK_SIZE_UDP_HDR, &addr); + break; + + case EOS_SOCK_MTYPE_OPEN_DGRAM: + sock = t_open_dgram(); + esock = 0; + if (sock > 0) { + xSemaphoreTake(mutex, portMAX_DELAY); + for (i=0; i<EOS_SOCK_MAX_SOCK; i++) { + if (_socks[i] == 0) { + esock = i+1; + _socks[i] = sock; + } + } + xSemaphoreGive(mutex); + } + // xTaskCreatePinnedToCore(&sock_receiver, "sock_receiver", EOS_TASK_SSIZE_UDP_RCVR, (void *)esock, EOS_TASK_PRIORITY_UDP_RCVR, NULL, 1); + xTaskCreate(&udp_rcvr_task, "udp_rcvr", EOS_TASK_SSIZE_UDP_RCVR, (void *)esock, EOS_TASK_PRIORITY_UDP_RCVR, NULL); + rbuf = eos_net_alloc(); + rbuf[0] = EOS_SOCK_MTYPE_OPEN_DGRAM; + rbuf[1] = esock; + eos_net_send(EOS_NET_MTYPE_SOCK, rbuf, 2, 0); + break; + + case EOS_SOCK_MTYPE_CLOSE: + if (size < 2) return; + sock = _socks[buffer[1]-1]; + t_close(sock); + break; + + default: + break; + } +} + +void eos_sock_init(void) { + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); + eos_net_set_handler(EOS_NET_MTYPE_SOCK, sock_handler); + ESP_LOGI(TAG, "INIT"); +}
\ No newline at end of file diff --git a/fw/esp32/components/eos/unicode.c b/fw/esp32/components/eos/unicode.c new file mode 120000 index 0000000..4cdffa7 --- /dev/null +++ b/fw/esp32/components/eos/unicode.c @@ -0,0 +1 @@ +../../../fe310/eos/unicode.c
\ No newline at end of file diff --git a/fw/esp32/components/eos/wifi.c b/fw/esp32/components/eos/wifi.c new file mode 100755 index 0000000..3dd90ba --- /dev/null +++ b/fw/esp32/components/eos/wifi.c @@ -0,0 +1,302 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/task.h> + +#include <esp_system.h> +#include <esp_event.h> +#include <esp_event_loop.h> +#include <esp_log.h> +#include <esp_err.h> +#include <esp_wifi.h> + +#include "eos.h" +#include "net.h" +#include "wifi.h" + +// XXX: WiFi fail due to no DHCP server + +#define WIFI_MAX_SCAN_RECORDS 20 +#define WIFI_MAX_CONNECT_ATTEMPTS 3 + +#define WIFI_STATE_STOPPED 0 +#define WIFI_STATE_SCANNING 1 +#define WIFI_STATE_CONNECTING 2 +#define WIFI_STATE_CONNECTED 3 +#define WIFI_STATE_DISCONNECTING 4 +#define WIFI_STATE_DISCONNECTED 5 + +#define WIFI_ACTION_NONE 0 +#define WIFI_ACTION_SCAN 1 +#define WIFI_ACTION_CONNECT 2 +#define WIFI_ACTION_DISCONNECT 3 + +static const char *TAG = "EOS WIFI"; + +static SemaphoreHandle_t mutex; + +static wifi_config_t wifi_sta_config; +static wifi_scan_config_t wifi_scan_config; + +static int wifi_connect_cnt = 0; +static uint8_t wifi_action; +static uint8_t wifi_state; + +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) { + esp_err_t ret = ESP_OK; + char _disconnect; + uint8_t _action, _state; + unsigned char *rbuf; + wifi_ap_record_t scan_r[WIFI_MAX_SCAN_RECORDS]; + uint16_t scan_n = WIFI_MAX_SCAN_RECORDS; + + switch(event->event_id) { + case WIFI_EVENT_SCAN_DONE: + memset(scan_r, 0, sizeof(scan_r)); + esp_wifi_scan_get_ap_records(&scan_n, scan_r); + + xSemaphoreTake(mutex, portMAX_DELAY); + _state = wifi_state; + if (wifi_state == WIFI_STATE_CONNECTED) wifi_action = WIFI_ACTION_NONE; + xSemaphoreGive(mutex); + + if (_state != WIFI_STATE_CONNECTED) ret = esp_wifi_stop(); + break; + + case WIFI_EVENT_STA_START: + xSemaphoreTake(mutex, portMAX_DELAY); + _action = wifi_action; + xSemaphoreGive(mutex); + + switch (_action) { + case WIFI_ACTION_SCAN: + ret = esp_wifi_scan_start(&wifi_scan_config, 0); + break; + + case WIFI_ACTION_CONNECT: + ret = esp_wifi_connect(); + break; + + default: + break; + } + break; + + case WIFI_EVENT_STA_STOP: + xSemaphoreTake(mutex, portMAX_DELAY); + wifi_state = WIFI_STATE_STOPPED; + wifi_action = WIFI_ACTION_NONE; + xSemaphoreGive(mutex); + break; + + case WIFI_EVENT_STA_CONNECTED: + xSemaphoreTake(mutex, portMAX_DELAY); + wifi_state = WIFI_STATE_CONNECTED; + wifi_action = WIFI_ACTION_NONE; + wifi_connect_cnt = WIFI_MAX_CONNECT_ATTEMPTS; + xSemaphoreGive(mutex); + break; + + case WIFI_EVENT_STA_DISCONNECTED: + xSemaphoreTake(mutex, portMAX_DELAY); + if (wifi_connect_cnt) wifi_connect_cnt--; + _action = wifi_action; + _disconnect = (wifi_connect_cnt == 0); + if (_disconnect) wifi_state = WIFI_STATE_DISCONNECTED; + xSemaphoreGive(mutex); + + if (_disconnect) { + rbuf = eos_net_alloc(); + if (_action == WIFI_ACTION_CONNECT) { + rbuf[0] = EOS_WIFI_MTYPE_CONNECT; + rbuf[1] = EOS_ERR; + eos_net_send(EOS_NET_MTYPE_WIFI, rbuf, 2, 0); + } else { + rbuf[0] = EOS_WIFI_MTYPE_DISCONNECT; + eos_net_send(EOS_NET_MTYPE_WIFI, rbuf, 1, 0); + } + if (!_action) ret = esp_wifi_stop(); + } else { + ret = esp_wifi_connect(); + } + break; + + case IP_EVENT_STA_GOT_IP: + ESP_LOGD(TAG, "IP address: " IPSTR, IP2STR(&event->event_info.got_ip.ip_info.ip)); + if (event->event_info.got_ip.ip_changed) { + // send wifi reconnect + } else { + rbuf = eos_net_alloc(); + rbuf[0] = EOS_WIFI_MTYPE_CONNECT; + rbuf[1] = EOS_OK; + eos_net_send(EOS_NET_MTYPE_WIFI, rbuf, 2, 0); + } + break; + + default: // Ignore the other event types + break; + } + if (ret != ESP_OK) ESP_LOGD(TAG, "ESP WIFI ERR: %d", ret); + + return ESP_OK; +} + +static void wifi_handler(unsigned char _mtype, unsigned char *buffer, uint16_t size) { + int rv = EOS_OK; + uint8_t mtype = buffer[0]; + char *ssid, *pass; + + switch (mtype) { + case EOS_WIFI_MTYPE_SCAN: + rv = eos_wifi_scan(); + break; + + case EOS_WIFI_MTYPE_CONNECT: + ssid = (char *)buffer+1; + pass = ssid+strlen(ssid)+1; + rv = eos_wifi_set_auth(ssid, pass); + if (!rv) rv = eos_wifi_connect(); + break; + + case EOS_WIFI_MTYPE_DISCONNECT: + rv = eos_wifi_disconnect(); + break; + } + if (rv) ESP_LOGD(TAG, "WIFI HANDLER ERR: %d", rv); +} + +void eos_wifi_init(void) { + esp_err_t ret; + wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT(); + + memset(&wifi_sta_config, 0, sizeof(wifi_sta_config)); + + ret = esp_event_loop_init(wifi_event_handler, NULL); + assert(ret == ESP_OK); + + ret = esp_wifi_init(&wifi_config); + assert(ret == ESP_OK); + + ret = esp_wifi_set_storage(WIFI_STORAGE_RAM); + assert(ret == ESP_OK); + + ret = esp_wifi_set_mode(WIFI_MODE_STA); + assert(ret == ESP_OK); + + ret = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config); + assert(ret == ESP_OK); + + ret = esp_wifi_stop(); + assert(ret == ESP_OK); + + mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(mutex); + + eos_net_set_handler(EOS_NET_MTYPE_WIFI, wifi_handler); + ESP_LOGI(TAG, "INIT"); +} + +int eos_wifi_scan(void) { + int rv = EOS_OK; + esp_err_t ret = ESP_OK; + uint8_t _wifi_state = 0; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (!wifi_action) { + _wifi_state = wifi_state; + + wifi_action = WIFI_ACTION_SCAN; + if (wifi_state == WIFI_STATE_STOPPED) wifi_state = WIFI_STATE_SCANNING; + + memset(&wifi_scan_config, 0, sizeof(wifi_scan_config)); + } else { + rv = EOS_ERR_BUSY; + } + xSemaphoreGive(mutex); + + if (rv) return rv; + + if (_wifi_state == WIFI_STATE_STOPPED) { + ret = esp_wifi_start(); + } else { + ret = esp_wifi_scan_start(&wifi_scan_config, 0); + } + if (ret != ESP_OK) rv = EOS_ERR; + + return rv; +} + +int eos_wifi_set_auth(char *ssid, char *pass) { + int rv = EOS_OK; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (!wifi_action) { + if (ssid) strncpy((char *)wifi_sta_config.sta.ssid, ssid, sizeof(wifi_sta_config.sta.ssid) - 1); + if (pass) strncpy((char *)wifi_sta_config.sta.password, pass, sizeof(wifi_sta_config.sta.password) - 1); + } else { + rv = EOS_ERR_BUSY; + + } + xSemaphoreGive(mutex); + + return rv; +} + +int eos_wifi_connect(void) { + int rv = EOS_OK; + esp_err_t ret = ESP_OK; + uint8_t _wifi_state = 0; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (!wifi_action) { + _wifi_state = wifi_state; + + wifi_action = WIFI_ACTION_CONNECT; + wifi_state = WIFI_STATE_CONNECTING; + wifi_connect_cnt = WIFI_MAX_CONNECT_ATTEMPTS; + } else { + rv = EOS_ERR_BUSY; + } + xSemaphoreGive(mutex); + + if (rv) return rv; + + esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config); + + if (_wifi_state == WIFI_STATE_STOPPED) { + ret = esp_wifi_start(); + } else { + ret = esp_wifi_connect(); + } + if (ret != ESP_OK) rv = EOS_ERR; + + return rv; +} + +int eos_wifi_disconnect(void) { + int rv = EOS_OK; + esp_err_t ret = ESP_OK; + + xSemaphoreTake(mutex, portMAX_DELAY); + if (!wifi_action) { + wifi_action = WIFI_ACTION_DISCONNECT; + wifi_state = WIFI_STATE_DISCONNECTING; + wifi_connect_cnt = 0; + + memset(wifi_sta_config.sta.ssid, 0, sizeof(wifi_sta_config.sta.ssid)); + memset(wifi_sta_config.sta.password, 0, sizeof(wifi_sta_config.sta.password)); + } else { + rv = EOS_ERR_BUSY; + } + xSemaphoreGive(mutex); + + if (rv) return rv; + + ret = esp_wifi_stop(); + if (ret != ESP_OK) rv = EOS_ERR; + + return rv; +} + diff --git a/fw/esp32/main/app_main.c b/fw/esp32/main/app_main.c new file mode 100644 index 0000000..4babcdc --- /dev/null +++ b/fw/esp32/main/app_main.c @@ -0,0 +1,38 @@ +#include <freertos/FreeRTOS.h> +#include <freertos/task.h> + +#include <tcpip_adapter.h> +#include <driver/gpio.h> +#include <esp_sleep.h> + +#include "i2c.h" +#include "cell.h" +#include "_net.h" +#include "wifi.h" +#include "sock.h" +#include "power.h" +#include "bq25895.h" + +#define ESP_INTR_FLAG_DEFAULT 0 + +// Main application +void app_main() { + tcpip_adapter_init(); + + eos_net_init(); + + eos_cell_pcm_init(); + gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); + eos_modem_init(); + + eos_cell_init(); + eos_wifi_init(); + eos_sock_init(); + + eos_power_init(); + + eos_i2c_init(); + eos_bq25895_set_ilim(); +} + + diff --git a/fw/esp32/main/component.mk b/fw/esp32/main/component.mk new file mode 100644 index 0000000..61f8990 --- /dev/null +++ b/fw/esp32/main/component.mk @@ -0,0 +1,8 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it will take the sources in the +# src/ directory, compile them and link them into lib(subdirectory_name).a +# in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# diff --git a/fw/fe310/Makefile b/fw/fe310/Makefile new file mode 100644 index 0000000..f1430fb --- /dev/null +++ b/fw/fe310/Makefile @@ -0,0 +1,25 @@ +include common.mk + +CFLAGS += -I./include + +subdirs = bsp/drivers bsp/gloss bsp/metal eos eos/eve eos/eve/screen eos/eve/widget + +all: libeos.a + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +libeos.a: + for i in $(subdirs); do \ + (cd $$i && $(MAKE)) || exit; \ + done + rm -f $@ + for i in $(subdirs); do \ + $(AR) rcs $@ $$i/*.o; \ + done + +clean: + for i in $(subdirs); do \ + (cd $$i && $(MAKE) clean) || exit; \ + done + rm -f *.o *.a diff --git a/fw/fe310/bsp/default.lds b/fw/fe310/bsp/default.lds new file mode 100644 index 0000000..cabcf01 --- /dev/null +++ b/fw/fe310/bsp/default.lds @@ -0,0 +1,153 @@ +OUTPUT_ARCH("riscv") + +ENTRY(_enter) + +MEMORY +{ + flash (rxai!w) : ORIGIN = 0x20000000, LENGTH = 0x6a120 + itim (wx!rai) : ORIGIN = 0x8000000, LENGTH = 0x2000 + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 0x4000 +} + +PHDRS +{ + flash PT_LOAD; + ram PT_LOAD; + ram_init PT_LOAD; + itim PT_LOAD; + itim_init PT_LOAD; +} + +SECTIONS +{ + + __stack_size = 0x1000; + PROVIDE(__metal_boot_hart = 0); + PROVIDE(__metal_chicken_bit = 0); + + .init : { + KEEP (*(.text.metal.init.enter)) + KEEP (*(.text.metal.init.*)) + KEEP (*(SORT_NONE(.init))) + KEEP (*(.text.libgloss.start)) + } >flash AT>flash :flash + + .fini : { + KEEP (*(SORT_NONE(.fini))) + } >flash AT>flash :flash + + .text : { + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + } >flash AT>flash :flash + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } >flash AT>flash :flash + + . = ALIGN(8); + + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >flash AT>flash :flash + + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >flash AT>flash :flash + + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >flash AT>flash :flash + + .ctors : { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >flash AT>flash :flash + + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >flash AT>flash :flash + + .itim : ALIGN(8) { + *(.itim .itim.*) + } >itim AT>flash :itim_init + + PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) ); + PROVIDE( metal_segment_itim_target_start = ADDR(.itim) ); + PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) ); + + .data : ALIGN(8) { + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.* .sdata2.*) + *(.gnu.linkonce.s.*) + } >itim AT>flash :itim_init +/* >ram AT>flash :ram_init */ + + PROVIDE( metal_segment_data_source_start = LOADADDR(.data) ); + PROVIDE( metal_segment_data_target_start = ADDR(.data) ); + PROVIDE( metal_segment_data_target_end = ADDR(.data) + SIZEOF(.data) ); + + .bss : ALIGN(8) { + *(.ibss .ibss.*) + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + } >itim AT>ram :itim +/* >ram AT>ram :ram */ + + PROVIDE( metal_segment_bss_target_start = ADDR(.bss) ); + PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) ); + + __heap_size = 0x4000 - __stack_size; + .heap : { + PROVIDE( metal_segment_heap_target_start = . ); + . += __heap_size; + PROVIDE( metal_segment_heap_target_end = . ); + PROVIDE( _heap_end = . ); + } >ram AT>ram :ram + + PROVIDE(__stack_size = __stack_size); + + .stack : { + PROVIDE(metal_segment_stack_begin = .); + . += __stack_size; + PROVIDE(metal_segment_stack_end = .); + PROVIDE( _sp = . ); + } >ram AT>ram :ram + +} + diff --git a/fw/fe310/bsp/drivers/Makefile b/fw/fe310/bsp/drivers/Makefile new file mode 100644 index 0000000..14fed05 --- /dev/null +++ b/fw/fe310/bsp/drivers/Makefile @@ -0,0 +1,10 @@ +include ../../common.mk +CFLAGS += -I../include -include sys/cdefs.h + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +all: plic_driver.o prci_driver.o + +clean: + rm -f *.o diff --git a/fw/fe310/bsp/drivers/plic_driver.c b/fw/fe310/bsp/drivers/plic_driver.c new file mode 100644 index 0000000..27b9d2c --- /dev/null +++ b/fw/fe310/bsp/drivers/plic_driver.c @@ -0,0 +1,127 @@ +// See LICENSE for license details. + +#include "sifive/devices/plic.h" +#include "plic_driver.h" +#include "platform.h" +#include "encoding.h" +#include <string.h> + + +// Note that there are no assertions or bounds checking on these +// parameter values. + +void volatile_memzero(uint8_t * base, unsigned int size) +{ + volatile uint8_t * ptr; + for (ptr = base; ptr < (base + size); ptr++){ + *ptr = 0; + } +} + +void PLIC_init ( + plic_instance_t * this_plic, + uintptr_t base_addr, + uint32_t num_sources, + uint32_t num_priorities + ) +{ + + this_plic->base_addr = base_addr; + this_plic->num_sources = num_sources; + this_plic->num_priorities = num_priorities; + + // Disable all interrupts (don't assume that these registers are reset). + unsigned long hart_id = read_csr(mhartid); + volatile_memzero((uint8_t*) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)), + (num_sources + 8) / 8); + + // Set all priorities to 0 (equal priority -- don't assume that these are reset). + volatile_memzero ((uint8_t *)(this_plic->base_addr + + PLIC_PRIORITY_OFFSET), + (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE); + + // Set the threshold to 0. + volatile plic_threshold* threshold = (plic_threshold*) + (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold = 0; + +} + +void PLIC_set_threshold (plic_instance_t * this_plic, + plic_threshold threshold){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold_ptr = threshold; + +} + + +void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current | ( 1 << (source & 0x7)); + *current_ptr = current; + +} + +void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current & ~(( 1 << (source & 0x7))); + *current_ptr = current; + +} + +void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){ + + if (this_plic->num_priorities > 0) { + volatile plic_priority * priority_ptr = (volatile plic_priority *) + (this_plic->base_addr + + PLIC_PRIORITY_OFFSET + + (source << PLIC_PRIORITY_SHIFT_PER_SOURCE)); + *priority_ptr = priority; + } +} + +plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){ + + unsigned long hart_id = read_csr(mhartid); + + volatile plic_source * claim_addr = (volatile plic_source * ) + (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + + return *claim_addr; + +} + +void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + *claim_addr = source; + +} + diff --git a/fw/fe310/bsp/drivers/plic_driver.h b/fw/fe310/bsp/drivers/plic_driver.h new file mode 100644 index 0000000..98b2bdd --- /dev/null +++ b/fw/fe310/bsp/drivers/plic_driver.h @@ -0,0 +1,51 @@ +// See LICENSE file for licence details + +#ifndef _PLIC_DRIVER_H_ +#define _PLIC_DRIVER_H_ + + +__BEGIN_DECLS + +#include "platform.h" + +typedef struct __plic_instance_t +{ + uintptr_t base_addr; + + uint32_t num_sources; + uint32_t num_priorities; + +} plic_instance_t; + +typedef uint32_t plic_source; +typedef uint32_t plic_priority; +typedef uint32_t plic_threshold; + +void PLIC_init ( + plic_instance_t * this_plic, + uintptr_t base_addr, + uint32_t num_sources, + uint32_t num_priorities + ); + +void PLIC_set_threshold (plic_instance_t * this_plic, + plic_threshold threshold); + +void PLIC_enable_interrupt (plic_instance_t * this_plic, + plic_source source); + +void PLIC_disable_interrupt (plic_instance_t * this_plic, + plic_source source); + +void PLIC_set_priority (plic_instance_t * this_plic, + plic_source source, + plic_priority priority); + +plic_source PLIC_claim_interrupt(plic_instance_t * this_plic); + +void PLIC_complete_interrupt(plic_instance_t * this_plic, + plic_source source); + +__END_DECLS + +#endif diff --git a/fw/fe310/bsp/drivers/prci_driver.c b/fw/fe310/bsp/drivers/prci_driver.c new file mode 100644 index 0000000..c2df2c9 --- /dev/null +++ b/fw/fe310/bsp/drivers/prci_driver.c @@ -0,0 +1,265 @@ +// See LICENSE file for license details + +#include "platform.h" + +#ifdef PRCI_CTRL_ADDR +#include "prci_driver.h" +#include <unistd.h> + +#define rdmcycle(x) { \ + uint32_t lo, hi, hi2; \ + __asm__ __volatile__ ("1:\n\t" \ + "csrr %0, mcycleh\n\t" \ + "csrr %1, mcycle\n\t" \ + "csrr %2, mcycleh\n\t" \ + "bne %0, %2, 1b\n\t" \ + : "=r" (hi), "=r" (lo), "=r" (hi2)) ; \ + *(x) = lo | ((uint64_t) hi << 32); \ + } + +uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq) +{ + + uint32_t start_mtime = CLINT_REG(CLINT_MTIME); + uint32_t end_mtime = start_mtime + mtime_ticks + 1; + + // Make sure we won't get rollover. + while (end_mtime < start_mtime) { + start_mtime = CLINT_REG(CLINT_MTIME); + end_mtime = start_mtime + mtime_ticks + 1; + } + + // Don't start measuring until mtime edge. + uint32_t tmp = start_mtime; + do { + start_mtime = CLINT_REG(CLINT_MTIME); + } while (start_mtime == tmp); + + uint64_t start_mcycle; + rdmcycle(&start_mcycle); + + while (CLINT_REG(CLINT_MTIME) < end_mtime) ; + + uint64_t end_mcycle; + rdmcycle(&end_mcycle); + uint32_t difference = (uint32_t) (end_mcycle - start_mcycle); + + uint64_t freq = ((uint64_t) difference * mtime_freq) / mtime_ticks; + return (uint32_t) freq & 0xFFFFFFFF; + +} + +unsigned long PRCI_get_cpu_freq() +{ + static uint32_t cpu_freq; + + if (!cpu_freq) { + // warm up I$ + PRCI_measure_mcycle_freq(3000, RTC_FREQ); + // measure for real + cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ); + } + + return cpu_freq; +} + +void PRCI_use_hfrosc(int div, int trim) +{ + // Make sure the HFROSC is running at its default setting + // It is OK to change this even if we are running off of it. + + PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1)); + + while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0); + + PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1); +} + +void PRCI_use_pll(int refsel, int bypass, + int r, int f, int q, int finaldiv, + int hfroscdiv, int hfrosctrim) +{ + // Ensure that we aren't running off the PLL before we mess with it. + if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) { + // Make sure the HFROSC is running at its default setting + PRCI_use_hfrosc(4, 16); + } + + // Set PLL Source to be HFXOSC if desired. + uint32_t config_value = 0; + + config_value |= PLL_REFSEL(refsel); + + if (bypass) { + // Bypass + config_value |= PLL_BYPASS(1); + + PRCI_REG(PRCI_PLLCFG) = config_value; + + // If we don't have an HFXTAL, this doesn't really matter. + // Set our Final output divide to divide-by-1: + PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0)); + } else { + + // To overclock, use the hfrosc + if (hfrosctrim >= 0 && hfroscdiv >= 0) { + PRCI_use_hfrosc(hfroscdiv, hfrosctrim); + } + + // Set DIV Settings for PLL + + // (Legal values of f_REF are 6-48MHz) + + // Set DIVR to divide-by-2 to get 8MHz frequency + // (legal values of f_R are 6-12 MHz) + + config_value |= PLL_BYPASS(1); + config_value |= PLL_R(r); + + // Set DIVF to get 512Mhz frequncy + // There is an implied multiply-by-2, 16Mhz. + // So need to write 32-1 + // (legal values of f_F are 384-768 MHz) + config_value |= PLL_F(f); + + // Set DIVQ to divide-by-2 to get 256 MHz frequency + // (legal values of f_Q are 50-400Mhz) + config_value |= PLL_Q(q); + + // Set our Final output divide: + if (finaldiv < 0) { + PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0)); + } else { + PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV(finaldiv)); + } + + PRCI_REG(PRCI_PLLCFG) = config_value; + + // Un-Bypass the PLL. + PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1); + + // Wait for PLL Lock + // Note that the Lock signal can be glitchy. + // Need to wait 100 us + // RTC is running at 32kHz. + // So wait 4 ticks of RTC. + uint32_t now = CLINT_REG(CLINT_MTIME); + while (CLINT_REG(CLINT_MTIME) - now < 4) ; + + // Now it is safe to check for PLL Lock + while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0); + + } + + // Switch over to PLL Clock source + PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1); + + // If we're running off HFXOSC, turn off the HFROSC to + // save power. + if (refsel) { + PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1); + } + +} + +void PRCI_use_default_clocks() +{ + // Turn off the LFROSC + AON_REG(AON_LFROSC) &= ~ROSC_EN(1); + + // Use HFROSC + PRCI_use_hfrosc(4, 16); +} + +void PRCI_use_hfxosc(uint32_t finaldiv) +{ + + PRCI_use_pll(1, // Use HFXTAL + 1, // Bypass = 1 + 0, // PLL settings don't matter + 0, // PLL settings don't matter + 0, // PLL settings don't matter + finaldiv, + -1, + -1); +} + +// This is a generic function, which +// doesn't span the entire range of HFROSC settings. +// It only adjusts the trim, which can span a hundred MHz or so. +// This function does not check the legality of the PLL settings +// at all, and it is quite possible to configure invalid PLL settings +// this way. +// It returns the actual measured CPU frequency. + +uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target ) +{ + + uint32_t hfrosctrim = 0; + uint32_t hfroscdiv = 4; + uint32_t prev_trim = 0; + + // In this function we use PLL settings which + // will give us a 32x multiplier from the output + // of the HFROSC source to the output of the + // PLL. We first measure our HFROSC to get the + // right trim, then finally use it as the PLL source. + // We should really check here that the f_cpu + // requested is something in the limit of the PLL. For + // now that is up to the user. + + // This will undershoot for frequencies not divisible by 16. + uint32_t desired_hfrosc_freq = (f_cpu / 16); + + PRCI_use_hfrosc(hfroscdiv, hfrosctrim); + + // Ignore the first run (for icache reasons) + uint32_t cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ); + + cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ); + uint32_t prev_freq = cpu_freq; + + while ((cpu_freq < desired_hfrosc_freq) && (hfrosctrim < 0x1F)){ + prev_trim = hfrosctrim; + prev_freq = cpu_freq; + hfrosctrim ++; + PRCI_use_hfrosc(hfroscdiv, hfrosctrim); + cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ); + } + + // We couldn't go low enough + if (prev_freq > desired_hfrosc_freq) { + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, prev_trim); + cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ); + return cpu_freq; + } + + // We couldn't go high enough + if (cpu_freq < desired_hfrosc_freq) { + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, prev_trim); + cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ); + return cpu_freq; + } + + // Check for over/undershoot + switch(target) { + case(PRCI_FREQ_CLOSEST): + if ((desired_hfrosc_freq - prev_freq) < (cpu_freq - desired_hfrosc_freq)) { + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, prev_trim); + } else { + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, hfrosctrim); + } + break; + case(PRCI_FREQ_UNDERSHOOT): + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, prev_trim); + break; + default: + PRCI_use_pll(0, 0, 1, 31, 1, -1, hfroscdiv, hfrosctrim); + } + + cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ); + return cpu_freq; + +} + +#endif diff --git a/fw/fe310/bsp/drivers/prci_driver.h b/fw/fe310/bsp/drivers/prci_driver.h new file mode 100644 index 0000000..14e1370 --- /dev/null +++ b/fw/fe310/bsp/drivers/prci_driver.h @@ -0,0 +1,80 @@ +// See LICENSE file for license details + +#ifndef _PRCI_DRIVER_H_ +#define _PRCI_DRIVER_H_ + +__BEGIN_DECLS + +#include <unistd.h> + +typedef enum prci_freq_target { + + PRCI_FREQ_OVERSHOOT, + PRCI_FREQ_CLOSEST, + PRCI_FREQ_UNDERSHOOT + +} PRCI_freq_target; + +/* Measure and return the approximate frequency of the + * CPU, as given by measuring the mcycle counter against + * the mtime ticks. + */ +uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq); +unsigned long PRCI_get_cpu_freq(); + +/* Safely switch over to the HFROSC using the given div + * and trim settings. + */ +void PRCI_use_hfrosc(int div, int trim); + +/* Safely switch over to the 16MHz HFXOSC, + * applying the finaldiv clock divider (1 is the lowest + * legal value). + */ +void PRCI_use_hfxosc(uint32_t finaldiv); + +/* Safely switch over to the PLL using the given + * settings. + * + * Note that not all combinations of the inputs are actually + * legal, and this function does not check for their + * legality ("safely" means that this function won't turn off + * or glitch the clock the CPU is actually running off, but + * doesn't protect against you making it too fast or slow.) + */ + +void PRCI_use_pll(int refsel, int bypass, + int r, int f, int q, int finaldiv, + int hfroscdiv, int hfrosctrim); + +/* Use the default clocks configured at reset. + * This is ~16Mhz HFROSC and turns off the LFROSC + * (on the current FE310 Dev Platforms, an external LFROSC is + * used as it is more power efficient). + */ +void PRCI_use_default_clocks(); + +/* This routine will adjust the HFROSC trim + * while using HFROSC as the clock source, + * measure the resulting frequency, then + * use it as the PLL clock source, + * in an attempt to get over, under, or close to the + * requested frequency. It returns the actual measured + * frequency. + * + * Note that the requested frequency must be within the + * range supported by the PLL so not all values are + * achievable with this function, and not all + * are guaranteed to actually work. The PLL + * is rated higher than the hardware. + * + * There is no check on the desired f_cpu frequency, it + * is up to the user to specify something reasonable. + */ + +uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target); + +__END_DECLS + +#endif + diff --git a/fw/fe310/bsp/gloss/Makefile b/fw/fe310/bsp/gloss/Makefile new file mode 100644 index 0000000..4376dce --- /dev/null +++ b/fw/fe310/bsp/gloss/Makefile @@ -0,0 +1,17 @@ +include ../../common.mk +CFLAGS += -I../include + +src = sys_access.c sys_chdir.c sys_chmod.c sys_chown.c sys_close.c sys_execve.c sys_exit.c sys_faccessat.c sys_fork.c sys_fstat.c sys_fstatat.c sys_ftime.c sys_getcwd.c sys_getpid.c \ + sys_isatty.c sys_kill.c sys_link.c sys_lseek.c sys_lstat.c sys_open.c sys_openat.c sys_read.c sys_sbrk.c sys_stat.c sys_sysconf.c sys_unlink.c sys_utime.c sys_wait.c sys_write.c +obj = crt0.o $(src:.c=.o) + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o diff --git a/fw/fe310/bsp/gloss/crt0.S b/fw/fe310/bsp/gloss/crt0.S new file mode 100644 index 0000000..920ee4b --- /dev/null +++ b/fw/fe310/bsp/gloss/crt0.S @@ -0,0 +1,246 @@ +/* Copyright (c) 2017-2018 SiFive Inc. All rights reserved. + + This copyrighted material is made available to anyone wishing to use, + modify, copy, or redistribute it subject to the terms and conditions + of the FreeBSD License. This program is distributed in the hope that + it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + including the implied warranties of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. A copy of this license is available at + http://www.opensource.org/licenses. +*/ + +/* crt0.S: Entry point for RISC-V METAL programs. */ + +.section .text.libgloss.start +.global _start +.type _start, @function + + /* _start is defined by the METAL to have been called with the following + * arguments: + * a0: the hart ID of the currently executing hart. Harts can start at + * any arbitrary point, it's the C library's job to ensure the code is + * safe. + * a1: a pointer to a description of the machine on which this code is + * currently executing. This is probably 0 on an embedded system + * because they tend to not be dynamically portable. As such, newlib + * ignores this argument. + * a2: a pointer to a function that must be run after the envirnoment has + * been initialized, but before user code can be expected to be run. + * If this is 0 then there is no function to be run. */ +_start: +.cfi_startproc +.cfi_undefined ra + + /* This is a bit funky: it's not usually sane for _start to return, but in + * this case we actually want to in order to signal an error to the METAL. */ + mv s0, ra + + /* Before doing anything we must initialize the global pointer, as we cannot + * safely perform any access that may be relaxed without GP being set. This + * is done with relaxation disabled to avoid relaxing the address calculation + * to just "addi gp, gp, 0". */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* The METAL is designed for a bare-metal environment and therefor is expected + * to define its own stack pointer. We also align the stack pointer here + * because the only RISC-V ABI that's currently defined mandates 16-byte + * stack alignment. */ + la sp, _sp + + /* Increment by hartid number of stack sizes */ + li t0, 0 + la t1, __stack_size +1: + beq t0, a0, 1f + add sp, sp, t1 + addi t0, t0, 1 + j 1b +1: + andi sp, sp, -16 + + /* If we're not hart 0, skip the initialization work */ + la t0, __metal_boot_hart + bne a0, t0, _skip_init + + /* Embedded systems frequently require relocating the data segment before C + * code can be run -- for example, the data segment may exist in flash upon + * boot and then need to get relocated into a non-persistant writable memory + * before C code can execute. If this is the case we do so here. This step + * is optional: if the METAL provides an environment in which this relocation + * is not necessary then it must simply set metal_segment_data_source_start to + * be equal to metal_segment_data_target_start. */ + la t0, metal_segment_data_source_start + la t1, metal_segment_data_target_start + la t2, metal_segment_data_target_end + + beq t0, t1, 2f + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + lw a0, 0(t0) + addi t0, t0, 4 + sw a0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + ld a0, 0(t0) + addi t0, t0, 8 + sd a0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* Copy the ITIM section */ + la t0, metal_segment_itim_source_start + la t1, metal_segment_itim_target_start + la t2, metal_segment_itim_target_end + + beq t0, t1, 2f + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + lw a0, 0(t0) + addi t0, t0, 4 + sw a0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + ld a0, 0(t0) + addi t0, t0, 8 + sd a0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* Fence all subsequent instruction fetches until after the ITIM writes + complete */ + fence.i + + /* Zero the BSS segment. */ + la t1, metal_segment_bss_target_start + la t2, metal_segment_bss_target_end + + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + sw x0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + sd x0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* At this point we're in an environment that can execute C code. The first + * thing to do is to make the callback to the parent environment if it's been + * requested to do so. */ + beqz a2, 1f + jalr a2 +1: + + /* The RISC-V port only uses new-style constructors and destructors. */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +_skip_init: + + /* Synchronize harts so that secondary harts wait until hart 0 finishes + initializing */ + call __metal_synchronize_harts + + /* Check RISC-V isa and enable FS bits if Floating Point architecture. */ + csrr a5, misa + li a4, 0x10028 + and a5, a5, a4 + beqz a5, 1f + csrr a5, mstatus + lui a4, 0x2 + or a5, a5, a4 + csrw mstatus, a5 + csrwi fcsr, 0 +1: + + /* This is a C runtime, so main() is defined to have some arguments. Since + * there's nothing sane the METAL can pass we don't bother with that but + * instead just setup as close to a NOP as we can. */ + li a0, 1 /* argc=1 */ + la a1, argv /* argv = {"libgloss", NULL} */ + la a2, envp /* envp = {NULL} */ + call secondary_main + + /* Call exit to handle libc's cleanup routines. Under normal contains this + * shouldn't even get called, but I'm still not using a tail call here + * because returning to the METAL is the right thing to do in pathological + * situations. */ + call exit + + /* And here's where we return. Again, it's a bit odd but the METAL defines + * this as a bad idea (ie, as opposed to leaving it undefined) and at this + * point it's really the only thing left to do. */ + mv ra, s0 + ret + +.cfi_endproc + +/* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we + * define _{init,fini} to do nothing. */ +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: +_fini: + ret +.size _init, .-_init +.size _fini, .-_fini + +/* By default, secondary_main will cause secondary harts to spin forever. + * Users can redefine secondary_main themselves to run code on secondary harts */ +.weak secondary_main +.global secondary_main +.type secondary_main, @function + +secondary_main: + addi sp, sp, -16 +#if __riscv_xlen == 32 + sw ra, 4(sp) +#else + sd ra, 8(sp) +#endif + csrr t0, mhartid + la t1, __metal_boot_hart + beq t0, t1, 2f +1: + wfi + j 1b +2: + call main +#if __riscv_xlen == 32 + lw ra, 4(sp) +#else + ld ra, 8(sp) +#endif + addi sp, sp, 16 + ret + +/* This shim allows main() to be passed a set of arguments that can satisfy the + * requirements of the C API. */ +.section .rodata.libgloss.start +argv: +.dc.a name +envp: +.dc.a 0 +name: +.asciz "libgloss" + diff --git a/fw/fe310/bsp/gloss/sys_access.c b/fw/fe310/bsp/gloss/sys_access.c new file mode 100644 index 0000000..c0bc153 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_access.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_access(const char *file, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_chdir.c b/fw/fe310/bsp/gloss/sys_chdir.c new file mode 100644 index 0000000..f33d26a --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_chdir.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_chdir(const char *path) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_chmod.c b/fw/fe310/bsp/gloss/sys_chmod.c new file mode 100644 index 0000000..67412bf --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_chmod.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/types.h> + +int +_chmod(const char *path, mode_t mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_chown.c b/fw/fe310/bsp/gloss/sys_chown.c new file mode 100644 index 0000000..302952e --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_chown.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <errno.h> + +int +_chown(const char *path, uid_t owner, gid_t group) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_close.c b/fw/fe310/bsp/gloss/sys_close.c new file mode 100644 index 0000000..26dd6a5 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_close.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_close(int file) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_execve.c b/fw/fe310/bsp/gloss/sys_execve.c new file mode 100644 index 0000000..9ae9f7e --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_execve.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_execve(const char *name, char *const argv[], char *const env[]) +{ + errno = ENOMEM; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_exit.c b/fw/fe310/bsp/gloss/sys_exit.c new file mode 100644 index 0000000..1502b3e --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_exit.c @@ -0,0 +1,7 @@ +#include <stdlib.h> + +__attribute__ ((noreturn)) void +_exit(int st) { while (1); } + +int +atexit(void (*f)(void)) { return 0; } diff --git a/fw/fe310/bsp/gloss/sys_faccessat.c b/fw/fe310/bsp/gloss/sys_faccessat.c new file mode 100644 index 0000000..873d52c --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_faccessat.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_faccessat(int dirfd, const char *file, int mode, int flags) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_fork.c b/fw/fe310/bsp/gloss/sys_fork.c new file mode 100644 index 0000000..64e6756 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_fork.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_fork() +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_fstat.c b/fw/fe310/bsp/gloss/sys_fstat.c new file mode 100644 index 0000000..fedc289 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_fstat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_fstat(int file, struct stat *st) +{ + errno = -ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_fstatat.c b/fw/fe310/bsp/gloss/sys_fstatat.c new file mode 100644 index 0000000..f2f43bd --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_fstatat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_fstatat(int dirfd, const char *file, struct stat *st, int flags) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_ftime.c b/fw/fe310/bsp/gloss/sys_ftime.c new file mode 100644 index 0000000..65c1563 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_ftime.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/timeb.h> + +int +_ftime(struct timeb *tp) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_getcwd.c b/fw/fe310/bsp/gloss/sys_getcwd.c new file mode 100644 index 0000000..82e8404 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_getcwd.c @@ -0,0 +1,8 @@ +#include <errno.h> + +char * +_getcwd(char *buf, size_t size) +{ + errno = -ENOSYS; + return NULL; +} diff --git a/fw/fe310/bsp/gloss/sys_getpid.c b/fw/fe310/bsp/gloss/sys_getpid.c new file mode 100644 index 0000000..589ad11 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_getpid.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int +_getpid() +{ + return 1; +} diff --git a/fw/fe310/bsp/gloss/sys_isatty.c b/fw/fe310/bsp/gloss/sys_isatty.c new file mode 100644 index 0000000..70aec43 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_isatty.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int +_isatty(int fd) +{ + return ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO) || (fd == STDERR_FILENO)); +} diff --git a/fw/fe310/bsp/gloss/sys_kill.c b/fw/fe310/bsp/gloss/sys_kill.c new file mode 100644 index 0000000..9003f26 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_kill.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_kill(int pid, int sig) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_link.c b/fw/fe310/bsp/gloss/sys_link.c new file mode 100644 index 0000000..40d5912 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_link.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int _link(const char *old_name, const char *new_name) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_lseek.c b/fw/fe310/bsp/gloss/sys_lseek.c new file mode 100644 index 0000000..d28a781 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_lseek.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <errno.h> + +off_t +_lseek(int file, off_t ptr, int dir) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_lstat.c b/fw/fe310/bsp/gloss/sys_lstat.c new file mode 100644 index 0000000..97a4585 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_lstat.c @@ -0,0 +1,8 @@ +#include <errno.h> +#include <sys/stat.h> + +int _lstat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_open.c b/fw/fe310/bsp/gloss/sys_open.c new file mode 100644 index 0000000..a59f627 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_open.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_open(const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_openat.c b/fw/fe310/bsp/gloss/sys_openat.c new file mode 100644 index 0000000..206de3b --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_openat.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_openat(int dirfd, const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_read.c b/fw/fe310/bsp/gloss/sys_read.c new file mode 100644 index 0000000..1857fc6 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_read.c @@ -0,0 +1,23 @@ +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> + +#include "platform.h" + +/* Read from a file. */ +ssize_t +_read(int fd, void *ptr, size_t len) +{ + if (fd != STDIN_FILENO) { + errno = ENOSYS; + return -1; + } + + char *current = ptr; + for (size_t i = 0; i < len; i++) { + volatile uint32_t r; + while ((r = UART0_REG(UART_REG_RXFIFO)) & 0x80000000); + current[i] = r & 0xFF; + } + return len; +} diff --git a/fw/fe310/bsp/gloss/sys_sbrk.c b/fw/fe310/bsp/gloss/sys_sbrk.c new file mode 100644 index 0000000..ce10c90 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_sbrk.c @@ -0,0 +1,38 @@ +#include <sys/types.h> + +/* brk is handled entirely within the C library. This limits METAL programs that + * use the C library to be disallowed from dynamically allocating memory + * without talking to the C library, but that sounds like a sane way to go + * about it. Note that there is no error checking anywhere in this file, users + * will simply get the relevant error when actually trying to use the memory + * that's been allocated. */ +extern char metal_segment_heap_target_start; +extern char metal_segment_heap_target_end; +static char *brk = &metal_segment_heap_target_start; + +int +_brk(void *addr) +{ + brk = addr; + return 0; +} + +char * +_sbrk(ptrdiff_t incr) +{ + char *old = brk; + + /* If __heap_size == 0, we can't allocate memory on the heap */ + if(&metal_segment_heap_target_start == &metal_segment_heap_target_end) { + return (void *)-1; + } + + /* Don't move the break past the end of the heap */ + if ((brk + incr) <= &metal_segment_heap_target_end) { + brk += incr; + } else { + return (void *)-1; + } + + return old; +} diff --git a/fw/fe310/bsp/gloss/sys_stat.c b/fw/fe310/bsp/gloss/sys_stat.c new file mode 100644 index 0000000..3c2e419 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_stat.c @@ -0,0 +1,9 @@ +#include <errno.h> +#include <sys/stat.h> + +int +_stat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_sysconf.c b/fw/fe310/bsp/gloss/sys_sysconf.c new file mode 100644 index 0000000..452a252 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_sysconf.c @@ -0,0 +1,16 @@ +#include <unistd.h> +#include <time.h> + +/* Get configurable system variables. */ + +long +_sysconf(int name) +{ + switch (name) + { + case _SC_CLK_TCK: + return CLOCKS_PER_SEC; + } + + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_unlink.c b/fw/fe310/bsp/gloss/sys_unlink.c new file mode 100644 index 0000000..b369d20 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_unlink.c @@ -0,0 +1,8 @@ +#include <errno.h> + +int +_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_utime.c b/fw/fe310/bsp/gloss/sys_utime.c new file mode 100644 index 0000000..33d557a --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_utime.c @@ -0,0 +1,9 @@ +#include <errno.h> +struct utimbuf; + +int +_utime(const char *path, const struct utimbuf *times) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_wait.c b/fw/fe310/bsp/gloss/sys_wait.c new file mode 100644 index 0000000..9d459f1 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_wait.c @@ -0,0 +1,7 @@ +#include <errno.h> + +int _wait(int *status) +{ + errno = ENOSYS; + return -1; +} diff --git a/fw/fe310/bsp/gloss/sys_write.c b/fw/fe310/bsp/gloss/sys_write.c new file mode 100644 index 0000000..2095940 --- /dev/null +++ b/fw/fe310/bsp/gloss/sys_write.c @@ -0,0 +1,22 @@ +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> + +#include "platform.h" + +/* Write to a file. */ +ssize_t +_write(int fd, const void *ptr, size_t len) +{ + if ((fd != STDOUT_FILENO) && (fd != STDERR_FILENO)) { + errno = ENOSYS; + return -1; + } + + const char *current = ptr; + for (size_t i = 0; i < len; i++) { + while (UART0_REG(UART_REG_TXFIFO) & 0x80000000); + UART0_REG(UART_REG_TXFIFO) = current[i]; + } + return len; +} diff --git a/fw/fe310/bsp/include/encoding.h b/fw/fe310/bsp/include/encoding.h new file mode 100644 index 0000000..35e0f9f --- /dev/null +++ b/fw/fe310/bsp/include/encoding.h @@ -0,0 +1,1313 @@ +// See LICENSE for license details. + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_PUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_VM 0x1F000000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_PUM 0x00040000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#ifdef __riscv64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif + +#endif + +#endif + +#endif +/* Automatically generated by parse-opcodes */ +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_URET 0x200073 +#define MASK_URET 0xffffffff +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_HRET 0x20200073 +#define MASK_HRET 0xffffffff +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_SFENCE_VM 0x10400073 +#define MASK_SFENCE_VM 0xfff07fff +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FMV_X_S 0xe0000053 +#define MASK_FMV_X_S 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FMV_S_X 0xf0000053 +#define MASK_FMV_S_X 0xfff0707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xffff +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_LI 0x4001 +#define MASK_C_LI 0xe003 +#define MATCH_C_LUI 0x6001 +#define MASK_C_LUI 0xe003 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_LWSP 0x4002 +#define MASK_C_LWSP 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_CUSTOM0 0xb +#define MASK_CUSTOM0 0x707f +#define MATCH_CUSTOM0_RS1 0x200b +#define MASK_CUSTOM0_RS1 0x707f +#define MATCH_CUSTOM0_RS1_RS2 0x300b +#define MASK_CUSTOM0_RS1_RS2 0x707f +#define MATCH_CUSTOM0_RD 0x400b +#define MASK_CUSTOM0_RD 0x707f +#define MATCH_CUSTOM0_RD_RS1 0x600b +#define MASK_CUSTOM0_RD_RS1 0x707f +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b +#define MASK_CUSTOM0_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM1 0x2b +#define MASK_CUSTOM1 0x707f +#define MATCH_CUSTOM1_RS1 0x202b +#define MASK_CUSTOM1_RS1 0x707f +#define MATCH_CUSTOM1_RS1_RS2 0x302b +#define MASK_CUSTOM1_RS1_RS2 0x707f +#define MATCH_CUSTOM1_RD 0x402b +#define MASK_CUSTOM1_RD 0x707f +#define MATCH_CUSTOM1_RD_RS1 0x602b +#define MASK_CUSTOM1_RD_RS1 0x707f +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b +#define MASK_CUSTOM1_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM2 0x5b +#define MASK_CUSTOM2 0x707f +#define MATCH_CUSTOM2_RS1 0x205b +#define MASK_CUSTOM2_RS1 0x707f +#define MATCH_CUSTOM2_RS1_RS2 0x305b +#define MASK_CUSTOM2_RS1_RS2 0x707f +#define MATCH_CUSTOM2_RD 0x405b +#define MASK_CUSTOM2_RD 0x707f +#define MATCH_CUSTOM2_RD_RS1 0x605b +#define MASK_CUSTOM2_RD_RS1 0x707f +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b +#define MASK_CUSTOM2_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM3 0x7b +#define MASK_CUSTOM3 0x707f +#define MATCH_CUSTOM3_RS1 0x207b +#define MASK_CUSTOM3_RS1 0x707f +#define MATCH_CUSTOM3_RS1_RS2 0x307b +#define MASK_CUSTOM3_RS1_RS2 0x707f +#define MATCH_CUSTOM3_RD 0x407b +#define MASK_CUSTOM3_RD 0x707f +#define MATCH_CUSTOM3_RD_RS1 0x607b +#define MASK_CUSTOM3_RD_RS1 0x707f +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b +#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_SBADADDR 0x143 +#define CSR_SIP 0x144 +#define CSR_SPTBR 0x180 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MBADADDR 0x343 +#define CSR_MIP 0x344 +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MUCOUNTEREN 0x320 +#define CSR_MSCOUNTEREN 0x321 +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif diff --git a/fw/fe310/bsp/include/platform.h b/fw/fe310/bsp/include/platform.h new file mode 100644 index 0000000..5178d86 --- /dev/null +++ b/fw/fe310/bsp/include/platform.h @@ -0,0 +1,129 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_PLATFORM_H +#define _SIFIVE_PLATFORM_H + +// Some things missing from the official encoding.h +#define MCAUSE_INT 0x80000000 +#define MCAUSE_CAUSE 0x7FFFFFFF + +#include <stdint.h> + +#include "sifive/const.h" +#include "sifive/devices/aon.h" +#include "sifive/devices/clint.h" +#include "sifive/devices/gpio.h" +#include "sifive/devices/otp.h" +#include "sifive/devices/plic.h" +#include "sifive/devices/prci.h" +#include "sifive/devices/pwm.h" +#include "sifive/devices/spi.h" +#include "sifive/devices/uart.h" + +/**************************************************************************** + * Platform definitions + *****************************************************************************/ + +// Memory map +#define MASKROM_MEM_ADDR _AC(0x00001000,UL) +#define TRAPVEC_TABLE_CTRL_ADDR _AC(0x00001010,UL) +#define OTP_MEM_ADDR _AC(0x00020000,UL) +#define CLINT_CTRL_ADDR _AC(0x02000000,UL) +#define PLIC_CTRL_ADDR _AC(0x0C000000,UL) +#define AON_CTRL_ADDR _AC(0x10000000,UL) +#define PRCI_CTRL_ADDR _AC(0x10008000,UL) +#define OTP_CTRL_ADDR _AC(0x10010000,UL) +#define GPIO_CTRL_ADDR _AC(0x10012000,UL) +#define UART0_CTRL_ADDR _AC(0x10013000,UL) +#define SPI0_CTRL_ADDR _AC(0x10014000,UL) +#define PWM0_CTRL_ADDR _AC(0x10015000,UL) +#define UART1_CTRL_ADDR _AC(0x10023000,UL) +#define SPI1_CTRL_ADDR _AC(0x10024000,UL) +#define PWM1_CTRL_ADDR _AC(0x10025000,UL) +#define SPI2_CTRL_ADDR _AC(0x10034000,UL) +#define PWM2_CTRL_ADDR _AC(0x10035000,UL) +#define SPI0_MEM_ADDR _AC(0x20000000,UL) +#define MEM_CTRL_ADDR _AC(0x80000000,UL) + +// IOF masks +#define IOF0_SPI1_MASK _AC(0x000007FC,UL) +#define SPI11_NUM_SS (4) +#define IOF_SPI1_SS0 (2u) +#define IOF_SPI1_SS1 (8u) +#define IOF_SPI1_SS2 (9u) +#define IOF_SPI1_SS3 (10u) +#define IOF_SPI1_MOSI (3u) +#define IOF_SPI1_MISO (4u) +#define IOF_SPI1_SCK (5u) +#define IOF_SPI1_DQ0 (3u) +#define IOF_SPI1_DQ1 (4u) +#define IOF_SPI1_DQ2 (6u) +#define IOF_SPI1_DQ3 (7u) + +#define IOF0_SPI2_MASK _AC(0xFC000000,UL) +#define SPI2_NUM_SS (1) +#define IOF_SPI2_SS0 (26u) +#define IOF_SPI2_MOSI (27u) +#define IOF_SPI2_MISO (28u) +#define IOF_SPI2_SCK (29u) +#define IOF_SPI2_DQ0 (27u) +#define IOF_SPI2_DQ1 (28u) +#define IOF_SPI2_DQ2 (30u) +#define IOF_SPI2_DQ3 (31u) + +//#define IOF0_I2C_MASK _AC(0x00003000,UL) + +#define IOF0_UART0_MASK _AC(0x00030000, UL) +#define IOF_UART0_RX (16u) +#define IOF_UART0_TX (17u) + +#define IOF0_UART1_MASK _AC(0x03000000, UL) +#define IOF_UART1_RX (24u) +#define IOF_UART1_TX (25u) + +#define IOF1_PWM0_MASK _AC(0x0000000F, UL) +#define IOF1_PWM1_MASK _AC(0x00780000, UL) +#define IOF1_PWM2_MASK _AC(0x00003C00, UL) + +// Interrupt numbers +#define INT_RESERVED 0 +#define INT_WDOGCMP 1 +#define INT_RTCCMP 2 +#define INT_UART0_BASE 3 +#define INT_UART1_BASE 4 +#define INT_SPI0_BASE 5 +#define INT_SPI1_BASE 6 +#define INT_SPI2_BASE 7 +#define INT_GPIO_BASE 8 +#define INT_PWM0_BASE 40 +#define INT_PWM1_BASE 44 +#define INT_PWM2_BASE 48 + +// Helper functions +#define _REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) +#define _REG32P(p, i) ((volatile uint32_t *) ((p) + (i))) +#define AON_REG(offset) _REG32(AON_CTRL_ADDR, offset) +#define CLINT_REG(offset) _REG32(CLINT_CTRL_ADDR, offset) +#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset) +#define OTP_REG(offset) _REG32(OTP_CTRL_ADDR, offset) +#define PLIC_REG(offset) _REG32(PLIC_CTRL_ADDR, offset) +#define PRCI_REG(offset) _REG32(PRCI_CTRL_ADDR, offset) +#define PWM0_REG(offset) _REG32(PWM0_CTRL_ADDR, offset) +#define PWM1_REG(offset) _REG32(PWM1_CTRL_ADDR, offset) +#define PWM2_REG(offset) _REG32(PWM2_CTRL_ADDR, offset) +#define SPI0_REG(offset) _REG32(SPI0_CTRL_ADDR, offset) +#define SPI1_REG(offset) _REG32(SPI1_CTRL_ADDR, offset) +#define SPI2_REG(offset) _REG32(SPI2_CTRL_ADDR, offset) +#define UART0_REG(offset) _REG32(UART0_CTRL_ADDR, offset) +#define UART1_REG(offset) _REG32(UART1_CTRL_ADDR, offset) + +// Misc + +#define PLIC_NUM_INTERRUPTS 52 +#define PLIC_NUM_PRIORITIES 7 + +#define RTC_FREQ 32768 + +void metal_init(void); + +#endif /* _SIFIVE_PLATFORM_H */ diff --git a/fw/fe310/bsp/include/sifive/bits.h b/fw/fe310/bsp/include/sifive/bits.h new file mode 100644 index 0000000..bfe656f --- /dev/null +++ b/fw/fe310/bsp/include/sifive/bits.h @@ -0,0 +1,36 @@ +// See LICENSE for license details. +#ifndef _RISCV_BITS_H +#define _RISCV_BITS_H + +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) + +#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b)) +#define ROUNDDOWN(a, b) ((a)/(b)*(b)) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi) + +#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1))) +#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) + +#define STR(x) XSTR(x) +#define XSTR(x) #x + +#if __riscv_xlen == 64 +# define SLL32 sllw +# define STORE sd +# define LOAD ld +# define LWU lwu +# define LOG_REGBYTES 3 +#else +# define SLL32 sll +# define STORE sw +# define LOAD lw +# define LWU lw +# define LOG_REGBYTES 2 +#endif +#define REGBYTES (1 << LOG_REGBYTES) + +#endif diff --git a/fw/fe310/bsp/include/sifive/const.h b/fw/fe310/bsp/include/sifive/const.h new file mode 100644 index 0000000..8dcffbb --- /dev/null +++ b/fw/fe310/bsp/include/sifive/const.h @@ -0,0 +1,18 @@ +// See LICENSE for license details. +/* Derived from <linux/const.h> */ + +#ifndef _SIFIVE_CONST_H +#define _SIFIVE_CONST_H + +#ifdef __ASSEMBLER__ +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define _AC(X,Y) (X##Y) +#define _AT(T,X) ((T)(X)) +#endif /* !__ASSEMBLER__*/ + +#define _BITUL(x) (_AC(1,UL) << (x)) +#define _BITULL(x) (_AC(1,ULL) << (x)) + +#endif /* _SIFIVE_CONST_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/aon.h b/fw/fe310/bsp/include/sifive/devices/aon.h new file mode 100644 index 0000000..63f1db3 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/aon.h @@ -0,0 +1,88 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_AON_H +#define _SIFIVE_AON_H + +/* Register offsets */ + +#define AON_WDOGCFG 0x000 +#define AON_WDOGCOUNT 0x008 +#define AON_WDOGS 0x010 +#define AON_WDOGFEED 0x018 +#define AON_WDOGKEY 0x01C +#define AON_WDOGCMP 0x020 + +#define AON_RTCCFG 0x040 +#define AON_RTCLO 0x048 +#define AON_RTCHI 0x04C +#define AON_RTCS 0x050 +#define AON_RTCCMP 0x060 + +#define AON_BACKUP0 0x080 +#define AON_BACKUP1 0x084 +#define AON_BACKUP2 0x088 +#define AON_BACKUP3 0x08C +#define AON_BACKUP4 0x090 +#define AON_BACKUP5 0x094 +#define AON_BACKUP6 0x098 +#define AON_BACKUP7 0x09C +#define AON_BACKUP8 0x0A0 +#define AON_BACKUP9 0x0A4 +#define AON_BACKUP10 0x0A8 +#define AON_BACKUP11 0x0AC +#define AON_BACKUP12 0x0B0 +#define AON_BACKUP13 0x0B4 +#define AON_BACKUP14 0x0B8 +#define AON_BACKUP15 0x0BC + +#define AON_PMUWAKEUPI0 0x100 +#define AON_PMUWAKEUPI1 0x104 +#define AON_PMUWAKEUPI2 0x108 +#define AON_PMUWAKEUPI3 0x10C +#define AON_PMUWAKEUPI4 0x110 +#define AON_PMUWAKEUPI5 0x114 +#define AON_PMUWAKEUPI6 0x118 +#define AON_PMUWAKEUPI7 0x11C +#define AON_PMUSLEEPI0 0x120 +#define AON_PMUSLEEPI1 0x124 +#define AON_PMUSLEEPI2 0x128 +#define AON_PMUSLEEPI3 0x12C +#define AON_PMUSLEEPI4 0x130 +#define AON_PMUSLEEPI5 0x134 +#define AON_PMUSLEEPI6 0x138 +#define AON_PMUSLEEPI7 0x13C +#define AON_PMUIE 0x140 +#define AON_PMUCAUSE 0x144 +#define AON_PMUSLEEP 0x148 +#define AON_PMUKEY 0x14C + +#define AON_LFROSC 0x070 +/* Constants */ + +#define AON_WDOGKEY_VALUE 0x51F15E +#define AON_WDOGFEED_VALUE 0xD09F00D + +#define AON_WDOGCFG_SCALE 0x0000000F +#define AON_WDOGCFG_RSTEN 0x00000100 +#define AON_WDOGCFG_ZEROCMP 0x00000200 +#define AON_WDOGCFG_ENALWAYS 0x00001000 +#define AON_WDOGCFG_ENCOREAWAKE 0x00002000 +#define AON_WDOGCFG_CMPIP 0x10000000 + +#define AON_RTCCFG_SCALE 0x0000000F +#define AON_RTCCFG_ENALWAYS 0x00001000 +#define AON_RTCCFG_CMPIP 0x10000000 + +#define AON_WAKEUPCAUSE_RESET 0x00 +#define AON_WAKEUPCAUSE_RTC 0x01 +#define AON_WAKEUPCAUSE_DWAKEUP 0x02 +#define AON_WAKEUPCAUSE_AWAKEUP 0x03 + +#define AON_RESETCAUSE_POWERON 0x0000 +#define AON_RESETCAUSE_EXTERNAL 0x0100 +#define AON_RESETCAUSE_WATCHDOG 0x0200 + +#define AON_PMUCAUSE_WAKEUPCAUSE 0x00FF +#define AON_PMUCAUSE_RESETCAUSE 0xFF00 + +#endif /* _SIFIVE_AON_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/clint.h b/fw/fe310/bsp/include/sifive/devices/clint.h new file mode 100644 index 0000000..cd3e0c7 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/clint.h @@ -0,0 +1,14 @@ +// See LICENSE for license details + +#ifndef _SIFIVE_CLINT_H +#define _SIFIVE_CLINT_H + + +#define CLINT_MSIP 0x0000 +#define CLINT_MSIP_size 0x4 +#define CLINT_MTIMECMP 0x4000 +#define CLINT_MTIMECMP_size 0x8 +#define CLINT_MTIME 0xBFF8 +#define CLINT_MTIME_size 0x8 + +#endif /* _SIFIVE_CLINT_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/gpio.h b/fw/fe310/bsp/include/sifive/devices/gpio.h new file mode 100644 index 0000000..f7f0acb --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/gpio.h @@ -0,0 +1,24 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_GPIO_H +#define _SIFIVE_GPIO_H + +#define GPIO_INPUT_VAL (0x00) +#define GPIO_INPUT_EN (0x04) +#define GPIO_OUTPUT_EN (0x08) +#define GPIO_OUTPUT_VAL (0x0C) +#define GPIO_PULLUP_EN (0x10) +#define GPIO_DRIVE (0x14) +#define GPIO_RISE_IE (0x18) +#define GPIO_RISE_IP (0x1C) +#define GPIO_FALL_IE (0x20) +#define GPIO_FALL_IP (0x24) +#define GPIO_HIGH_IE (0x28) +#define GPIO_HIGH_IP (0x2C) +#define GPIO_LOW_IE (0x30) +#define GPIO_LOW_IP (0x34) +#define GPIO_IOF_EN (0x38) +#define GPIO_IOF_SEL (0x3C) +#define GPIO_OUTPUT_XOR (0x40) + +#endif /* _SIFIVE_GPIO_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/otp.h b/fw/fe310/bsp/include/sifive/devices/otp.h new file mode 100644 index 0000000..93833e2 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/otp.h @@ -0,0 +1,23 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_OTP_H +#define _SIFIVE_OTP_H + +/* Register offsets */ + +#define OTP_LOCK 0x00 +#define OTP_CK 0x04 +#define OTP_OE 0x08 +#define OTP_SEL 0x0C +#define OTP_WE 0x10 +#define OTP_MR 0x14 +#define OTP_MRR 0x18 +#define OTP_MPP 0x1C +#define OTP_VRREN 0x20 +#define OTP_VPPEN 0x24 +#define OTP_A 0x28 +#define OTP_D 0x2C +#define OTP_Q 0x30 +#define OTP_READ_TIMINGS 0x34 + +#endif diff --git a/fw/fe310/bsp/include/sifive/devices/plic.h b/fw/fe310/bsp/include/sifive/devices/plic.h new file mode 100644 index 0000000..e1ca5d6 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/plic.h @@ -0,0 +1,31 @@ +// See LICENSE for license details. + +#ifndef PLIC_H +#define PLIC_H + +#include <sifive/const.h> + +// 32 bits per source +#define PLIC_PRIORITY_OFFSET _AC(0x0000,UL) +#define PLIC_PRIORITY_SHIFT_PER_SOURCE 2 +// 1 bit per source (1 address) +#define PLIC_PENDING_OFFSET _AC(0x1000,UL) +#define PLIC_PENDING_SHIFT_PER_SOURCE 0 + +//0x80 per target +#define PLIC_ENABLE_OFFSET _AC(0x2000,UL) +#define PLIC_ENABLE_SHIFT_PER_TARGET 7 + + +#define PLIC_THRESHOLD_OFFSET _AC(0x200000,UL) +#define PLIC_CLAIM_OFFSET _AC(0x200004,UL) +#define PLIC_THRESHOLD_SHIFT_PER_TARGET 12 +#define PLIC_CLAIM_SHIFT_PER_TARGET 12 + +#define PLIC_MAX_SOURCE 1023 +#define PLIC_SOURCE_MASK 0x3FF + +#define PLIC_MAX_TARGET 15871 +#define PLIC_TARGET_MASK 0x3FFF + +#endif /* PLIC_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/prci.h b/fw/fe310/bsp/include/sifive/devices/prci.h new file mode 100644 index 0000000..1a3de58 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/prci.h @@ -0,0 +1,56 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_PRCI_H +#define _SIFIVE_PRCI_H + +/* Register offsets */ + +#define PRCI_HFROSCCFG (0x0000) +#define PRCI_HFXOSCCFG (0x0004) +#define PRCI_PLLCFG (0x0008) +#define PRCI_PLLDIV (0x000C) +#define PRCI_PROCMONCFG (0x00F0) + +/* Fields */ +#define ROSC_DIV(x) (((x) & 0x2F) << 0 ) +#define ROSC_TRIM(x) (((x) & 0x1F) << 16) +#define ROSC_EN(x) (((x) & 0x1 ) << 30) +#define ROSC_RDY(x) (((x) & 0x1 ) << 31) + +#define XOSC_EN(x) (((x) & 0x1) << 30) +#define XOSC_RDY(x) (((x) & 0x1) << 31) + +#define PLL_R(x) (((x) & 0x7) << 0) +// single reserved bit for F LSB. +#define PLL_F(x) (((x) & 0x3F) << 4) +#define PLL_Q(x) (((x) & 0x3) << 10) +#define PLL_SEL(x) (((x) & 0x1) << 16) +#define PLL_REFSEL(x) (((x) & 0x1) << 17) +#define PLL_BYPASS(x) (((x) & 0x1) << 18) +#define PLL_LOCK(x) (((x) & 0x1) << 31) + +#define PLL_R_default 0x1 +#define PLL_F_default 0x1F +#define PLL_Q_default 0x3 + +#define PLL_REFSEL_HFROSC 0x0 +#define PLL_REFSEL_HFXOSC 0x1 + +#define PLL_SEL_HFROSC 0x0 +#define PLL_SEL_PLL 0x1 + +#define PLL_FINAL_DIV(x) (((x) & 0x3F) << 0) +#define PLL_FINAL_DIV_BY_1(x) (((x) & 0x1 ) << 8) + +#define PROCMON_DIV(x) (((x) & 0x1F) << 0) +#define PROCMON_TRIM(x) (((x) & 0x1F) << 8) +#define PROCMON_EN(x) (((x) & 0x1) << 16) +#define PROCMON_SEL(x) (((x) & 0x3) << 24) +#define PROCMON_NT_EN(x) (((x) & 0x1) << 28) + +#define PROCMON_SEL_HFCLK 0 +#define PROCMON_SEL_HFXOSCIN 1 +#define PROCMON_SEL_PLLOUTDIV 2 +#define PROCMON_SEL_PROCMON 3 + +#endif // _SIFIVE_PRCI_H diff --git a/fw/fe310/bsp/include/sifive/devices/pwm.h b/fw/fe310/bsp/include/sifive/devices/pwm.h new file mode 100644 index 0000000..067889a --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/pwm.h @@ -0,0 +1,37 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_PWM_H +#define _SIFIVE_PWM_H + +/* Register offsets */ + +#define PWM_CFG 0x00 +#define PWM_COUNT 0x08 +#define PWM_S 0x10 +#define PWM_CMP0 0x20 +#define PWM_CMP1 0x24 +#define PWM_CMP2 0x28 +#define PWM_CMP3 0x2C + +/* Constants */ + +#define PWM_CFG_SCALE 0x0000000F +#define PWM_CFG_STICKY 0x00000100 +#define PWM_CFG_ZEROCMP 0x00000200 +#define PWM_CFG_DEGLITCH 0x00000400 +#define PWM_CFG_ENALWAYS 0x00001000 +#define PWM_CFG_ONESHOT 0x00002000 +#define PWM_CFG_CMP0CENTER 0x00010000 +#define PWM_CFG_CMP1CENTER 0x00020000 +#define PWM_CFG_CMP2CENTER 0x00040000 +#define PWM_CFG_CMP3CENTER 0x00080000 +#define PWM_CFG_CMP0GANG 0x01000000 +#define PWM_CFG_CMP1GANG 0x02000000 +#define PWM_CFG_CMP2GANG 0x04000000 +#define PWM_CFG_CMP3GANG 0x08000000 +#define PWM_CFG_CMP0IP 0x10000000 +#define PWM_CFG_CMP1IP 0x20000000 +#define PWM_CFG_CMP2IP 0x40000000 +#define PWM_CFG_CMP3IP 0x80000000 + +#endif /* _SIFIVE_PWM_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/spi.h b/fw/fe310/bsp/include/sifive/devices/spi.h new file mode 100644 index 0000000..47b4693 --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/spi.h @@ -0,0 +1,80 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_SPI_H +#define _SIFIVE_SPI_H + +/* Register offsets */ + +#define SPI_REG_SCKDIV 0x00 +#define SPI_REG_SCKMODE 0x04 +#define SPI_REG_CSID 0x10 +#define SPI_REG_CSDEF 0x14 +#define SPI_REG_CSMODE 0x18 + +#define SPI_REG_DCSSCK 0x28 +#define SPI_REG_DSCKCS 0x2a +#define SPI_REG_DINTERCS 0x2c +#define SPI_REG_DINTERXFR 0x2e + +#define SPI_REG_FMT 0x40 +#define SPI_REG_TXFIFO 0x48 +#define SPI_REG_RXFIFO 0x4c +#define SPI_REG_TXCTRL 0x50 +#define SPI_REG_RXCTRL 0x54 + +#define SPI_REG_FCTRL 0x60 +#define SPI_REG_FFMT 0x64 + +#define SPI_REG_IE 0x70 +#define SPI_REG_IP 0x74 + +/* Fields */ + +#define SPI_SCK_PHA 0x1 +#define SPI_SCK_POL 0x2 + +#define SPI_FMT_PROTO(x) ((x) & 0x3) +#define SPI_FMT_ENDIAN(x) (((x) & 0x1) << 2) +#define SPI_FMT_DIR(x) (((x) & 0x1) << 3) +#define SPI_FMT_LEN(x) (((x) & 0xf) << 16) + +/* TXCTRL register */ +#define SPI_TXWM(x) ((x) & 0xffff) +/* RXCTRL register */ +#define SPI_RXWM(x) ((x) & 0xffff) + +#define SPI_IP_TXWM 0x1 +#define SPI_IP_RXWM 0x2 + +#define SPI_FCTRL_EN 0x1 + +#define SPI_INSN_CMD_EN 0x1 +#define SPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1) +#define SPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4) +#define SPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8) +#define SPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10) +#define SPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12) +#define SPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16) +#define SPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24) + +#define SPI_TXFIFO_FULL (1 << 31) +#define SPI_RXFIFO_EMPTY (1 << 31) + +/* Values */ + +#define SPI_CSMODE_AUTO 0 +#define SPI_CSMODE_HOLD 2 +#define SPI_CSMODE_OFF 3 + +#define SPI_DIR_RX 0 +#define SPI_DIR_TX 1 + +#define SPI_PROTO_S 0 +#define SPI_PROTO_D 1 +#define SPI_PROTO_Q 2 + +#define SPI_ENDIAN_MSB 0 +#define SPI_ENDIAN_LSB 1 + + +#endif /* _SIFIVE_SPI_H */ diff --git a/fw/fe310/bsp/include/sifive/devices/uart.h b/fw/fe310/bsp/include/sifive/devices/uart.h new file mode 100644 index 0000000..71bea6f --- /dev/null +++ b/fw/fe310/bsp/include/sifive/devices/uart.h @@ -0,0 +1,27 @@ +// See LICENSE for license details. + +#ifndef _SIFIVE_UART_H +#define _SIFIVE_UART_H + +/* Register offsets */ +#define UART_REG_TXFIFO 0x00 +#define UART_REG_RXFIFO 0x04 +#define UART_REG_TXCTRL 0x08 +#define UART_REG_RXCTRL 0x0c +#define UART_REG_IE 0x10 +#define UART_REG_IP 0x14 +#define UART_REG_DIV 0x18 + +/* TXCTRL register */ +#define UART_TXEN 0x1 +#define UART_TXWM(x) (((x) & 0xffff) << 16) + +/* RXCTRL register */ +#define UART_RXEN 0x1 +#define UART_RXWM(x) (((x) & 0xffff) << 16) + +/* IP register */ +#define UART_IP_TXWM 0x1 +#define UART_IP_RXWM 0x2 + +#endif /* _SIFIVE_UART_H */ diff --git a/fw/fe310/bsp/metal/Makefile b/fw/fe310/bsp/metal/Makefile new file mode 100644 index 0000000..32acfd2 --- /dev/null +++ b/fw/fe310/bsp/metal/Makefile @@ -0,0 +1,13 @@ +include ../../common.mk +CFLAGS += -I../include -I../drivers + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: entry.o metal.o + +clean: + rm -f *.o diff --git a/fw/fe310/bsp/metal/entry.S b/fw/fe310/bsp/metal/entry.S new file mode 100644 index 0000000..97da3fd --- /dev/null +++ b/fw/fe310/bsp/metal/entry.S @@ -0,0 +1,106 @@ +/* Copyright 2018 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* This code executes before _start, which is contained inside the C library. + * In embedded systems we want to ensure that _enter, which contains the first + * code to be executed, can be loaded at a specific address. To enable this + * feature we provide the '.text.metal.init.enter' section, which is + * defined to have the first address being where execution should start. */ +.section .text.metal.init.enter +.global _enter +_enter: + .cfi_startproc + + /* Inform the debugger that there is nowhere to backtrace past _enter. */ + .cfi_undefined ra + + /* The absolute first thing that must happen is configuring the global + * pointer register, which must be done with relaxation disabled because + * it's not valid to obtain the address of any symbol without GP + * configured. The C environment might go ahead and do this again, but + * that's safe as it's a fixed register. */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* Set up a simple trap vector to catch anything that goes wrong early in + * the boot process. */ + la t0, early_trap_vector + csrw mtvec, t0 + /* enable chicken bit if core is bullet series*/ + la t0, __metal_chicken_bit + beqz t0, 1f + csrwi 0x7C1, 0 +1: + + /* There may be pre-initialization routines inside the MBI code that run in + * C, so here we set up a C environment. First we set up a stack pointer, + * which is left as a weak reference in order to allow initialization + * routines that do not need a stack to be set up to transparently be + * called. */ + .weak __metal_stack_pointer + la sp, __metal_stack_pointer + + /* Check for an initialization routine and call it if one exists, otherwise + * just skip over the call entirely. Note that __metal_initialize isn't + * actually a full C function, as it doesn't end up with the .bss or .data + * segments having been initialized. This is done to avoid putting a + * burden on systems that can be initialized without having a C environment + * set up. */ + .weak __metal_before_start + la ra, __metal_before_start + beqz ra, 1f + jalr ra +1: + + /* At this point we can enter the C runtime's startup file. The arguments + * to this function are designed to match those provided to the SEE, just + * so we don't have to write another ABI. */ + csrr a0, mhartid + li a1, 0 + li a2, 0 + call _start + + /* If we've made it back here then there's probably something wrong. We + * allow the METAL to register a handler here. */ + .weak __metal_after_main + la ra, __metal_after_main + beqz ra, 1f + jalr ra +1: + + /* If that handler returns then there's not a whole lot we can do. Just + * try to make some noise. */ + la t0, 1f + csrw mtvec, t0 +1: + lw t1, 0(x0) + j 1b + + .cfi_endproc + +/* For sanity's sake we set up an early trap vector that just does nothing. If + * you end up here then there's a bug in the early boot code somewhere. */ +.section .text.metal.init.trapvec +.align 2 +early_trap_vector: + .cfi_startproc + csrr t0, mcause + csrr t1, mepc + csrr t2, mtval + j early_trap_vector + .cfi_endproc + +/* The GCC port might not emit a __register_frame_info symbol, which eventually + * results in a weak undefined reference that eventually causes crash when it + * is dereference early in boot. We really shouldn't need to put this here, + * but to deal with what I think is probably a bug in the linker script I'm + * going to leave this in for now. At least it's fairly cheap :) */ +.weak __register_frame_info +.global __register_frame_info +.section .text.metal.init.__register_frame_info +__register_frame_info: + .cfi_startproc + ret + .cfi_endproc diff --git a/fw/fe310/bsp/metal/metal.c b/fw/fe310/bsp/metal/metal.c new file mode 100644 index 0000000..00849b9 --- /dev/null +++ b/fw/fe310/bsp/metal/metal.c @@ -0,0 +1,34 @@ +#include <sys/cdefs.h> + +#include "encoding.h" +#include "platform.h" +#include "prci_driver.h" + +extern void eos_trap_entry(); + +static void uart_init(size_t baud_rate) { + GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK; + GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK; + UART0_REG(UART_REG_DIV) = PRCI_get_cpu_freq() / baud_rate - 1; + UART0_REG(UART_REG_TXCTRL) |= UART_TXEN; + UART0_REG(UART_REG_RXCTRL) |= UART_RXEN; +} + +__attribute__((constructor)) +void metal_init(void) { + SPI0_REG(SPI_REG_SCKDIV) = 8; + + PRCI_use_default_clocks(); + PRCI_use_pll(PLL_REFSEL_HFXOSC, 0, 1, 31, 1, -1, -1, -1); + uart_init(115200); + + write_csr(mtvec, &eos_trap_entry); + if (read_csr(misa) & (1 << ('F' - 'A'))) { // if F extension is present + write_csr(mstatus, MSTATUS_FS); // allow FPU instructions without trapping + write_csr(fcsr, 0); // initialize rounding mode, undefined at reset + } +} + +__attribute__((section(".init"))) +void __metal_synchronize_harts() { +} diff --git a/fw/fe310/bsp/openocd.cfg b/fw/fe310/bsp/openocd.cfg new file mode 100644 index 0000000..1205cbd --- /dev/null +++ b/fw/fe310/bsp/openocd.cfg @@ -0,0 +1,34 @@ +#write_config_file +# JTAG adapter setup +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "FT2232H-56Q MiniModule" +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 + +#Reset Stretcher logic on FE310 is ~1 second long +#This doesn't apply if you use +# ftdi_set_signal, but still good to document +#adapter_nsrst_delay 1500 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank spi0 fespi 0x20000000 0 0 0 $_TARGETNAME.0 0x10014000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +sleep 1500 +} +halt + +# flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/fw/fe310/bsp/upload b/fw/fe310/bsp/upload new file mode 100755 index 0000000..a52fc0a --- /dev/null +++ b/fw/fe310/bsp/upload @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e +set -o pipefail + +unset elf +unset hex +unset cfg +unset openocd +unset jlink +unset gdb +while [[ "$1" != "" ]] +do + case "$1" + in + --elf) elf="$2"; shift 2;; + --hex) hex="$2"; shift 2;; + --openocd) openocd="$2"; shift 2;; + --openocd-config) cfg="$2"; shift 2;; + --jlink) jlink="$2"; shift 2;; + --gdb) gdb="$2"; shift 2;; + *) echo "$0: Unknown argument $1"; exit 1;; + esac +done + +if [ "$elf" == "" -a "$hex" == "" ] +then + echo "$0: --elf or --hex is required" >&2 + exit 1 +fi + +export GDB_PORT=3333 + +if [ "$jlink" != "" ] +then + +echo -e "loadfile $hex\nrnh\nexit" | $jlink -device FE310 -if JTAG -speed 4000 -jtagconf -1,-1 -autoconnect 1 + +else + +$openocd -f $cfg & + +$gdb $elf --batch -ex "set remotetimeout 240" -ex "target extended-remote localhost:${GDB_PORT}" -ex "monitor reset halt" -ex "monitor flash protect 0 64 last off" -ex "load" -ex "monitor resume" -ex "monitor shutdown" -ex "quit" + +kill %1 + +fi diff --git a/fw/fe310/common.mk b/fw/fe310/common.mk new file mode 100644 index 0000000..e468289 --- /dev/null +++ b/fw/fe310/common.mk @@ -0,0 +1,8 @@ +CC = $(RISCV_HOME)/bin/riscv64-unknown-elf-gcc +AR = $(RISCV_HOME)/bin/riscv64-unknown-elf-ar +RANLIB = $(RISCV_HOME)/bin/riscv64-unknown-elf-ranlib + +CFLAGS = -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs -O3 +LDFLAGS = $(CFLAGS) -L$(FE310_HOME) -Wl,--gc-sections -nostartfiles -nostdlib -Wl,--start-group -lc -lm -lgcc -leos -Wl,--end-group -T$(FE310_HOME)/bsp/default.lds + +UPARGS = --openocd $(RISCV_OPENOCD_HOME)/bin/openocd --gdb $(RISCV_HOME)/bin/riscv64-unknown-elf-gdb --openocd-config $(FE310_HOME)/bsp/openocd.cfg diff --git a/fw/fe310/eos/LICENSE b/fw/fe310/eos/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/fw/fe310/eos/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/fw/fe310/eos/Makefile b/fw/fe310/eos/Makefile new file mode 100644 index 0000000..301a30e --- /dev/null +++ b/fw/fe310/eos/Makefile @@ -0,0 +1,17 @@ +include ../common.mk + +CFLAGS += -I../bsp/include -I../bsp/drivers + +obj = trap_entry.o eos.o msgq.o event.o interrupt.o timer.o power.o i2s.o uart.o spi.o spi_dev.o net.o wifi.o cell.o sock.o unicode.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o
\ No newline at end of file diff --git a/fw/fe310/eos/cell.c b/fw/fe310/eos/cell.c new file mode 100644 index 0000000..2421f4b --- /dev/null +++ b/fw/fe310/eos/cell.c @@ -0,0 +1,48 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "eos.h" +#include "event.h" +#include "net.h" + +#include "cell.h" + +static eos_evt_handler_t evt_handler[EOS_CELL_MAX_MTYPE]; + +static void cell_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + if ((buffer == NULL) || (len < 1)) { + eos_net_bad_handler(type, buffer, len); + return; + } + unsigned char mtype = buffer[0]; + unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4; + + if (idx < EOS_CELL_MAX_MTYPE) { + evt_handler[idx](type, buffer, len); + } else { + eos_net_bad_handler(type, buffer, len); + } +} + +static void cell_handle_rdy(unsigned char type, unsigned char *buffer, uint16_t len) { + // Do nothing + eos_net_free(buffer, 0); +} + +void eos_cell_init(void) { + int i; + + for (i=0; i<EOS_CELL_MAX_MTYPE; i++) { + evt_handler[i] = eos_net_bad_handler; + } + eos_net_set_handler(EOS_NET_MTYPE_CELL, cell_handle_evt); + eos_cell_set_handler(EOS_CELL_MTYPE_READY, cell_handle_rdy); +} + +void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler) { + unsigned char idx = (mtype & EOS_CELL_MTYPE_MASK) >> 4; + + if (handler == NULL) handler = eos_net_bad_handler; + if (idx < EOS_CELL_MAX_MTYPE) evt_handler[idx] = handler; +} diff --git a/fw/fe310/eos/cell.h b/fw/fe310/eos/cell.h new file mode 100644 index 0000000..d93967a --- /dev/null +++ b/fw/fe310/eos/cell.h @@ -0,0 +1,38 @@ +#include <stdint.h> +#include "event.h" + +#define EOS_CELL_MTYPE_DEV 0x00 +#define EOS_CELL_MTYPE_VOICE 0x10 +#define EOS_CELL_MTYPE_SMS 0x20 +#define EOS_CELL_MTYPE_CBS 0x30 +#define EOS_CELL_MTYPE_USSD 0x40 +#define EOS_CELL_MTYPE_DATA 0x70 + +#define EOS_CELL_MTYPE_MASK 0xf0 +#define EOS_CELL_MAX_MTYPE 8 + +#define EOS_CELL_MTYPE_READY 0 +#define EOS_CELL_MTYPE_UART_DATA 1 +#define EOS_CELL_MTYPE_UART_TAKE 2 +#define EOS_CELL_MTYPE_UART_GIVE 3 +#define EOS_CELL_MTYPE_PCM_DATA 4 +#define EOS_CELL_MTYPE_PCM_START 5 +#define EOS_CELL_MTYPE_PCM_STOP 6 + +#define EOS_CELL_MTYPE_VOICE_DIAL 1 +#define EOS_CELL_MTYPE_VOICE_RING 2 +#define EOS_CELL_MTYPE_VOICE_ANSWER 3 +#define EOS_CELL_MTYPE_VOICE_HANGUP 4 +#define EOS_CELL_MTYPE_VOICE_BEGIN 5 +#define EOS_CELL_MTYPE_VOICE_END 6 + +#define EOS_CELL_MTYPE_USSD_REQUEST 1 +#define EOS_CELL_MTYPE_USSD_REPLY 2 + +#define EOS_CELL_UART_MODE_NONE 0 +#define EOS_CELL_UART_MODE_ATCMD 1 +#define EOS_CELL_UART_MODE_PPP 2 +#define EOS_CELL_UART_MODE_RELAY 3 + +void eos_cell_init(void); +void eos_cell_set_handler(unsigned char mtype, eos_evt_handler_t handler);
\ No newline at end of file diff --git a/fw/fe310/eos/eos.c b/fw/fe310/eos/eos.c new file mode 100644 index 0000000..b02abed --- /dev/null +++ b/fw/fe310/eos/eos.c @@ -0,0 +1,43 @@ +#include <stdio.h> + +#include "event.h" +#include "interrupt.h" +#include "timer.h" +#include "power.h" +#include "i2s.h" +#include "uart.h" +#include "spi.h" +#include "net.h" +#include "wifi.h" +#include "cell.h" +#include "sock.h" +#include "eve/eve.h" + +#include "eos.h" + +static uint32_t eve_touch[6] = {0xfa46,0xfffffcf6,0x422fe,0xffffff38,0x10002,0xf3cb0}; + +void eos_init(void) { + uint8_t wakeup_cause = eos_power_wakeup_cause(); + printf("WAKE:%d\n", wakeup_cause); + + eos_evtq_init(); + eos_intr_init(); + eos_timer_init(); + eos_i2s_init(); + eos_uart_init(); + eos_spi_init(); + eos_net_init(); + eos_power_init(); + eos_wifi_init(); + eos_cell_init(); + eos_sock_init(); + eos_spi_dev_init(); + + eos_net_wake(wakeup_cause); + + eve_set_touch_calibration(eve_touch); + eos_spi_dev_start(EOS_DEV_DISP); + eve_init(wakeup_cause == EOS_PWR_WAKE_RST); + eos_spi_dev_stop(); +} diff --git a/fw/fe310/eos/eos.h b/fw/fe310/eos/eos.h new file mode 100644 index 0000000..2a295f1 --- /dev/null +++ b/fw/fe310/eos/eos.h @@ -0,0 +1,12 @@ +#define EOS_OK 0 +#define EOS_ERR -1 +#define EOS_ERR_TIMEOUT -2 +#define EOS_ERR_BUSY -3 + +#define EOS_ERR_FULL -10 +#define EOS_ERR_EMPTY -11 +#define EOS_ERR_NOTFOUND -12 + +#define EOS_ERR_NET -20 + +void eos_init(void); diff --git a/fw/fe310/eos/eve/Makefile b/fw/fe310/eos/eve/Makefile new file mode 100644 index 0000000..d700b30 --- /dev/null +++ b/fw/fe310/eos/eve/Makefile @@ -0,0 +1,17 @@ +include ../../common.mk + +CFLAGS += -I.. -I../../bsp/include + +obj = eve.o eve_touch.o eve_track.o eve_kbd.o eve_text.o eve_platform.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o
\ No newline at end of file diff --git a/fw/fe310/eos/eve/eve.c b/fw/fe310/eos/eve/eve.c new file mode 100644 index 0000000..1db5744 --- /dev/null +++ b/fw/fe310/eos/eve/eve.c @@ -0,0 +1,411 @@ +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> + +#include "eve.h" + +#define EVE_MEM_WRITE 0x800000 + +static char _cmd_burst; +static uint16_t _cmd_offset; +static uint32_t _dl_addr; +static uint32_t *_touch_calib; +static uint8_t _brigtness; +static uint8_t _power_state; + +void eve_command(uint8_t command, uint8_t parameter) { + eve_spi_cs_set(); + eve_spi_xchg24(((uint32_t)command << 16) | ((uint32_t)parameter << 8), 0); + eve_spi_cs_clear(); +} + +uint8_t eve_read8(uint32_t addr) { + uint8_t r; + eve_spi_cs_set(); + eve_spi_xchg32(addr << 8, 0); + r = eve_spi_xchg8(0, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); + + return r; +} + +uint16_t eve_read16(uint32_t addr) { + uint16_t r; + eve_spi_cs_set(); + eve_spi_xchg32(addr << 8, 0); + r = eve_spi_xchg16(0, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); + + return r; +} + +uint32_t eve_read32(uint32_t addr) { + uint32_t r; + eve_spi_cs_set(); + eve_spi_xchg32(addr << 8, 0); + r = eve_spi_xchg32(0, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); + + return r; +} + +void eve_write8(uint32_t addr, uint8_t data) { + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, 0); + eve_spi_xchg8(data, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); +} + +void eve_write16(uint32_t addr, uint16_t data) { + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, 0); + eve_spi_xchg16(data, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); +} + +void eve_write32(uint32_t addr, uint32_t data) { + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, 0); + eve_spi_xchg32(data, EVE_SPI_FLAG_BSWAP); + eve_spi_cs_clear(); +} + +void eve_readb(uint32_t addr, uint8_t *b, size_t size) { + int i; + + eve_spi_cs_set(); + eve_spi_xchg32(addr << 8, 0); + for (i=0; i<size; i++) { + b[i] = eve_spi_xchg8(0, 0); + } + eve_spi_cs_clear(); +} + +void eve_writeb(uint32_t addr, uint8_t *b, size_t size) { + int i; + + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, 0); + for (i=0; i<size; i++) { + eve_spi_xchg8(b[i], 0); + } + eve_spi_cs_clear(); +} + +static void _dl_inc(uint32_t i) { + _dl_addr += i; +} + +void eve_dl_start(uint32_t addr) { + _dl_addr = addr; +} + +void eve_dl_write(uint32_t dl) { + eve_write32(_dl_addr, dl); + _dl_inc(4); +} + +void eve_dl_swap(void) { + eve_write8(REG_DLSWAP, EVE_DLSWAP_FRAME); +} + +uint32_t eve_dl_get_addr(void) { + return _dl_addr; +} + +static void _cmd_inc(uint16_t i) { + _cmd_offset += i; + _cmd_offset &= 0x0fff; +} + +static void _cmd_begin(uint32_t command) { + uint8_t flags = 0; + + if (_cmd_burst) { + flags = EVE_SPI_FLAG_TX; + } else { + uint32_t addr = EVE_RAM_CMD + _cmd_offset; + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, 0); + } + eve_spi_xchg32(command, EVE_SPI_FLAG_BSWAP | flags); + _cmd_inc(4); +} + +static void _cmd_end(void) { + if (!_cmd_burst) eve_spi_cs_clear(); +} + +static void _cmd_string(const char *s, uint8_t flags) { + int i = 0; + + while (s[i] != 0) { + eve_spi_xchg8(s[i], flags); + i++; + } + eve_spi_xchg8(0, flags); + i++; + _cmd_inc(i); +} + +static void _cmd_buffer(const char *b, int size, uint8_t flags) { + int i = 0; + + for (i=0; i<size; i++) { + eve_spi_xchg8(b[i], flags); + } + _cmd_inc(size); +} + +void eve_cmd(uint32_t cmd, const char *fmt, ...) { + uint8_t flags = _cmd_burst ? (EVE_SPI_FLAG_TX | EVE_SPI_FLAG_BSWAP) : EVE_SPI_FLAG_BSWAP; + va_list argv; + uint16_t *p; + int i = 0; + + va_start(argv, fmt); + _cmd_begin(cmd); + while (fmt[i]) { + switch (fmt[i]) { + case 'b': + eve_spi_xchg8(va_arg(argv, int), flags); + _cmd_inc(1); + break; + case 'h': + eve_spi_xchg16(va_arg(argv, int), flags); + _cmd_inc(2); + break; + case 'w': + eve_spi_xchg32(va_arg(argv, int), flags); + _cmd_inc(4); + break; + case '&': + p = va_arg(argv, uint16_t *); + *p = _cmd_offset; + eve_spi_xchg32(0, flags); + _cmd_inc(4); + break; + case 's': + _cmd_string(va_arg(argv, const char *), flags); + break; + case 'p': + _cmd_buffer(va_arg(argv, const char *), va_arg(argv, int), flags); + break; + } + i++; + } + va_end(argv); + /* padding */ + i = _cmd_offset & 3; /* equivalent to _cmd_offset % 4 */ + if (i) { + i = 4 - i; /* 3, 2 or 1 */ + _cmd_inc(i); + + while (i > 0) { + eve_spi_xchg8(0, flags); + i--; + } + } + _cmd_end(); +} + +uint32_t eve_cmd_result(uint16_t offset) { + return eve_read32(EVE_RAM_CMD + offset); +} + +void eve_cmd_dl(uint32_t dl) { + _cmd_begin(dl); + _cmd_end(); +} + +int eve_cmd_done(void) { + uint16_t r = eve_read16(REG_CMD_READ); + if (r == 0xfff) { + _cmd_offset = 0; + eve_write8(REG_CPURESET, 1); + eve_write16(REG_CMD_READ, 0); + eve_write16(REG_CMD_WRITE, 0); + eve_write16(REG_CMD_DL, 0); + eve_write8(REG_CPURESET, 0); + return -1; + } + return (r == _cmd_offset); +} + +int eve_cmd_exec(int w) { + eve_write16(REG_CMD_WRITE, _cmd_offset); + if (w) { + int r; + do { + r = eve_cmd_done(); + } while (!r); + if (r < 0) return EVE_ERR; + } + return EVE_OK; +} + +void eve_cmd_burst_start(void) { + uint32_t addr = EVE_RAM_CMD + _cmd_offset; + eve_spi_cs_set(); + eve_spi_xchg24(addr | EVE_MEM_WRITE, EVE_SPI_FLAG_TX); + _cmd_burst = 1; +} + +void eve_cmd_burst_end(void) { + eve_spi_flush(); + eve_spi_cs_clear(); + _cmd_burst = 0; +} + +void eve_active(void) { + eve_command(EVE_ACTIVE, 0); + if (_power_state == EVE_PSTATE_SLEEP) eve_time_sleep(40); + + eve_write8(REG_PWM_DUTY, _brigtness); + if (_power_state != EVE_PSTATE_SLEEP) return; + + eve_write8(REG_TOUCH_MODE, EVE_TMODE_CONTINUOUS); + eve_write8(REG_CTOUCH_EXTENDED, 0x00); + + _power_state = EVE_PSTATE_ACTIVE; +} + +void eve_standby(void) { + if (_power_state != EVE_PSTATE_ACTIVE) return; + + _brigtness = eve_read8(REG_PWM_DUTY); + eve_command(EVE_STANDBY, 0); + + _power_state = EVE_PSTATE_STANDBY; +} + +void eve_sleep(void) { + if (_power_state != EVE_PSTATE_ACTIVE) return; + + _brigtness = eve_read8(REG_PWM_DUTY); + eve_write8(REG_PWM_DUTY, 0x0); + + eve_write8(REG_CTOUCH_EXTENDED, 0x01); + eve_write8(REG_TOUCH_MODE, EVE_TMODE_OFF); + + eve_time_sleep(500); + eve_command(EVE_SLEEP, 0); + + _power_state = EVE_PSTATE_SLEEP; +} + +void eve_brightness(uint8_t b) { + eve_write8(REG_PWM_DUTY, b); +} + +void eve_set_touch_calibration(uint32_t *matrix) { + _touch_calib = matrix; +} + +static int _init(void) { + uint8_t chipid = 0; + uint16_t timeout = 0; + + eve_command(EVE_RST_PULSE, 0); + eve_command(EVE_CLKEXT, 0); + eve_command(EVE_ACTIVE, 0); /* start EVE */ + + while (chipid != 0x7C) { /* if chipid is not 0x7c, continue to read it until it is, EVE needs a moment for it's power on self-test and configuration */ + eve_time_sleep(1); + chipid = eve_read8(REG_ID); + timeout++; + if (timeout > 400) return EVE_ERR; + } + + eve_write8(REG_PWM_DUTY, 0); + eve_write16(REG_GPIOX, 0); + + /* Initialize Display */ + eve_write16(REG_HCYCLE, EVE_HCYCLE); /* total number of clocks per line, incl front/back porch */ + eve_write16(REG_HOFFSET, EVE_HOFFSET); /* start of active line */ + eve_write16(REG_HSYNC0, EVE_HSYNC0); /* start of horizontal sync pulse */ + eve_write16(REG_HSYNC1, EVE_HSYNC1); /* end of horizontal sync pulse */ + eve_write16(REG_VCYCLE, EVE_VCYCLE); /* total number of lines per screen, including pre/post */ + eve_write16(REG_VOFFSET, EVE_VOFFSET); /* start of active screen */ + eve_write16(REG_VSYNC0, EVE_VSYNC0); /* start of vertical sync pulse */ + eve_write16(REG_VSYNC1, EVE_VSYNC1); /* end of vertical sync pulse */ + eve_write8(REG_SWIZZLE, EVE_SWIZZLE); /* FT8xx output to LCD - pin order */ + eve_write8(REG_PCLK_POL, EVE_PCLKPOL); /* LCD data is clocked in on this PCLK edge */ + eve_write8(REG_CSPREAD, EVE_CSPREAD); /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */ + eve_write16(REG_HSIZE, EVE_HSIZE); /* active display width */ + eve_write16(REG_VSIZE, EVE_VSIZE); /* active display height */ + + /* do not set PCLK yet - wait for just after the first display list */ + + /* disable Audio */ + eve_write16(REG_SOUND, 0x0000); /* set synthesizer to silence */ + eve_write8(REG_VOL_SOUND, 0x00); /* turn synthesizer volume off */ + eve_write8(REG_VOL_PB, 0x00); /* turn recorded audio volume off */ + + /* write a basic display-list to get things started */ + eve_dl_start(EVE_RAM_DL); + eve_dl_write(CLEAR_COLOR_RGB(0,0,0)); + eve_dl_write(CLEAR(1,1,1)); + eve_dl_write(DISPLAY()); + eve_dl_swap(); + + /* nothing is being displayed yet... the pixel clock is still 0x00 */ + eve_write16(REG_GPIOX, 0x8000); /* enable the DISP signal to the LCD panel, it is set to output in REG_GPIOX_DIR by default */ + eve_write8(REG_PCLK, EVE_PCLK); /* now start clocking data to the LCD panel */ + + /* configure Touch */ + eve_write16(REG_TOUCH_CONFIG, 0xb81); /* enable touch low power mode: 0xb81 - default: 0x381 */ + eve_write8(REG_TOUCH_MODE, EVE_TMODE_CONTINUOUS); /* enable touch */ + eve_write16(REG_TOUCH_RZTHRESH, EVE_TOUCH_RZTHRESH); /* eliminate any false touches */ + + if (_touch_calib) { + eve_write32(REG_TOUCH_TRANSFORM_A, _touch_calib[0]); + eve_write32(REG_TOUCH_TRANSFORM_B, _touch_calib[1]); + eve_write32(REG_TOUCH_TRANSFORM_C, _touch_calib[2]); + eve_write32(REG_TOUCH_TRANSFORM_D, _touch_calib[3]); + eve_write32(REG_TOUCH_TRANSFORM_E, _touch_calib[4]); + eve_write32(REG_TOUCH_TRANSFORM_F, _touch_calib[5]); + } else { + uint32_t touch_calib[6]; + eve_cmd_dl(CMD_DLSTART); + eve_cmd_dl(CLEAR_COLOR_RGB(0,0,0)); + eve_cmd_dl(CLEAR(1,1,1)); + eve_cmd(CMD_TEXT, "hhhhs", EVE_HSIZE/2, EVE_VSIZE/2, 27, EVE_OPT_CENTER, "Please tap on the dot."); + eve_cmd(CMD_CALIBRATE, "w", 0); + eve_cmd_dl(DISPLAY()); + eve_cmd_dl(CMD_SWAP); + eve_cmd_exec(1); + + touch_calib[0] = eve_read32(REG_TOUCH_TRANSFORM_A); + touch_calib[1] = eve_read32(REG_TOUCH_TRANSFORM_B); + touch_calib[2] = eve_read32(REG_TOUCH_TRANSFORM_C); + touch_calib[3] = eve_read32(REG_TOUCH_TRANSFORM_D); + touch_calib[4] = eve_read32(REG_TOUCH_TRANSFORM_E); + touch_calib[5] = eve_read32(REG_TOUCH_TRANSFORM_F); + + printf("TOUCH TRANSFORM:{0x%x,0x%x,0x%x,0x%x,0x%x,0x%x}\n", touch_calib[0], touch_calib[1], touch_calib[2], touch_calib[3], touch_calib[4], touch_calib[5]); + } + + eve_write8(REG_CTOUCH_EXTENDED, 0x00); + + eve_cmd(CMD_SETROTATE, "w", 2); + eve_cmd_exec(1); + + return EVE_OK; +} + +int eve_init(int pwr_on) { + if (pwr_on) { + int rv = _init(); + if (rv) return rv; + } else { + _power_state = EVE_PSTATE_SLEEP; + eve_active(); + } + + eve_touch_init(); + eve_track_init(); + eve_platform_init(); + + return EVE_OK; +} diff --git a/fw/fe310/eos/eve/eve.h b/fw/fe310/eos/eve/eve.h new file mode 100644 index 0000000..eb59959 --- /dev/null +++ b/fw/fe310/eos/eve/eve.h @@ -0,0 +1,59 @@ +#include <stdint.h> + +#include "eve_def.h" +#include "eve_touch.h" +#include "eve_track.h" +#include "eve_platform.h" + +#define EVE_OK 0 +#define EVE_ERR -1 + +#define EVE_PSTATE_ACTIVE 0 +#define EVE_PSTATE_STANDBY 1 +#define EVE_PSTATE_SLEEP 3 + +#define EVE_TAG_NOTAG 0 + +#define COLOR_RGBC(c) ((4UL<<24)|((c)&16777215UL)) +#define CLEAR_COLOR_RGBC(c) ((2UL<<24)|((c)&16777215UL)) + +typedef struct EVERect { + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} EVERect; + +void eve_command(uint8_t command, uint8_t parameter); + +uint8_t eve_read8(uint32_t addr); +uint16_t eve_read16(uint32_t addr); +uint32_t eve_read32(uint32_t addr); +void eve_write8(uint32_t addr, uint8_t data); +void eve_write16(uint32_t addr, uint16_t data); +void eve_write32(uint32_t addr, uint32_t data); + +void eve_readb(uint32_t addr, uint8_t *b, size_t size); +void eve_writeb(uint32_t addr, uint8_t *b, size_t size); + +void eve_dl_start(uint32_t addr); +void eve_dl_write(uint32_t dl); +void eve_dl_swap(void); +uint32_t eve_dl_get_addr(void); + +void eve_cmd(uint32_t cmd, const char *fmt, ...); +uint32_t eve_cmd_result(uint16_t offset); +void eve_cmd_dl(uint32_t dl); +int eve_cmd_done(void); +int eve_cmd_exec(int w); +void eve_cmd_burst_start(void); +void eve_cmd_burst_end(void); + +void eve_active(void); +void eve_standby(void); +void eve_sleep(void); +void eve_wake(void); +void eve_brightness(uint8_t b); +void eve_set_touch_calibration(uint32_t *matrix); + +int eve_init(int pwr_on); diff --git a/fw/fe310/eos/eve/eve_config.h b/fw/fe310/eos/eve/eve_config.h new file mode 100755 index 0000000..882ea89 --- /dev/null +++ b/fw/fe310/eos/eve/eve_config.h @@ -0,0 +1,39 @@ +#ifndef EVE_CONFIG_H_ +#define EVE_CONFIG_H_ + +/* my display */ + +#define EVE_TH 1200L +#define EVE_THD 800L +#define EVE_THF 210L +#define EVE_THP 20L +#define EVE_THB 46L + +#define EVE_TV 650L +#define EVE_TVD 480L +#define EVE_TVF 22L +#define EVE_TVP 12L +#define EVE_TVB 23L + + +#define EVE_HSIZE (EVE_THD) /* Thd Length of visible part of line (in PCLKs) - display width */ +#define EVE_HSYNC0 (EVE_THF) /* Thf Horizontal Front Porch */ +#define EVE_HSYNC1 (EVE_THF + EVE_THP) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ +#define EVE_HOFFSET (EVE_THF + EVE_THP + EVE_THB) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ +#define EVE_HCYCLE (EVE_TH) /* Th Total length of line (visible and non-visible) (in PCLKs) */ + +#define EVE_VSIZE (EVE_TVD) /* Tvd Number of visible lines (in lines) - display height */ +#define EVE_VSYNC0 (EVE_TVF) /* Tvf Vertical Front Porch */ +#define EVE_VSYNC1 (EVE_TVF + EVE_TVP) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ +#define EVE_VOFFSET (EVE_TVF + EVE_TVP + EVE_TVB) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ +#define EVE_VCYCLE (EVE_TV) /* Tv Total number of lines (visible and non-visible) (in lines) */ + +#define EVE_PCLKPOL (1L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ +#define EVE_SWIZZLE (0L) /* Defines the arrangement of the RGB pins of the FT800 */ +#define EVE_PCLK (1L) /* 60MHz / REG_PCLK = PCLK frequency - 30 MHz */ +#define EVE_CSPREAD (0L) /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */ +#define EVE_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ +#define EVE_HAS_CRYSTAL +#define FT81X_ENABLE + +#endif /* EVE_CONFIG_H */ diff --git a/fw/fe310/eos/eve/eve_def.h b/fw/fe310/eos/eve/eve_def.h new file mode 100755 index 0000000..25e4927 --- /dev/null +++ b/fw/fe310/eos/eve/eve_def.h @@ -0,0 +1,872 @@ +/*
+@file EVE.h
+@brief Contains FT80x/FT81x/BT81x API definitions
+@version 4.0
+@date 2019-11-17
+@author Rudolph Riedel
+
+@section LICENSE
+
+MIT License
+
+Copyright (c) 2016-2019 Rudolph Riedel
+
+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.
+
+@section History
+
+2.1
+- changes to this header
+
+2.2
+- commented out "#define DISPLAY() ((0UL<<24))" as it collides with a define in the Arduino IDE - the whole section of "macros" needs a rework...
+
+3.0
+- renamed from FT800.h to FT8.h
+- changed FT_ prefixes to FT8_
+- switched to standard-C compliant comment-style
+- changed FT81x register definitions from decimal to hex
+- verified all FT81x register definitions
+- moved FT81x registers marked as "reserved" to an #if 0 block
+
+3.1
+- moved several undocumented commands to an #if 0 block
+
+3.2
+- moved CMD_CRC to the block of undocumented commands as well
+
+3.3
+- changed macros BITMAP_LAYOUT_H and BITMAP_SIZE_H as submitted to github by "jventerprises"
+ These macros provide the extended bits for bitmaps bigger than 511 pixels, FTDIs original implementation that I used and never touched takes the arguments
+ as already processed and not the original values.
+ Note the one example in "FT81x Series Programmers Guide" Version 1.1 for displaying a 800x480 sized bitmap:
+ dl(BITMAP_SIZE_H(1, 0));
+ dl(BITMAP_SIZE(NEAREST, BORDER, BORDER, 288, 480));
+ Now you can use it like this:
+ EVE_cmd_dl(BITMAP_SIZE_H(800, 480));
+ EVE_cmd_dl(BITMAP_SIZE(NEAREST, BORDER, BORDER, 800, 480));
+
+4.0
+- renamed from FT8.h to EVE.h
+- renamed EVE_81X_ENABLE to FT81X_ENABLE
+- changed FT8_ prefixes to EVE_
+- rearranged things a bit with FT80x specific includes moved to the end and a "#if defined (BT81X_ENABLE)" block on top of the chip-specific includes
+- started to add specific BT81x defines
+- minor maintenance
+- changed OPT_FLASH to EVE_OPT_FLASH and OPT_FORMAT to EVE_OPT_FORMAT for consistency
+- added EVE_OPT_FILL which has been left out of the documentation for the BT81x so far
+- added a few BT81x specific macros
+- added a few FT81x/BT81x specific host commands
+- removed the preceding underscore from the include guard define to avoid potential undefined behavior
+- removed a bunch of defines for FT80x that I never implemented for FT81x
+
+*/
+
+#include "eve_config.h"
+
+#ifndef EVE_H_
+#define EVE_H_
+
+
+#define DL_CLEAR 0x26000000UL /* requires OR'd arguments */
+#define DL_CLEAR_RGB 0x02000000UL /* requires OR'd arguments */
+#define DL_COLOR_RGB 0x04000000UL /* requires OR'd arguments */
+#define DL_POINT_SIZE 0x0D000000UL /* requires OR'd arguments */
+#define DL_END 0x21000000UL
+#define DL_BEGIN 0x1F000000UL /* requires OR'd arguments */
+#define DL_DISPLAY 0x00000000UL
+
+#define CLR_COL 0x4
+#define CLR_STN 0x2
+#define CLR_TAG 0x1
+
+
+/* Host commands */
+#define EVE_ACTIVE 0x00 /* place FT8xx in active state */
+#define EVE_STANDBY 0x41 /* place FT8xx in Standby (clk running) */
+#define EVE_SLEEP 0x42 /* place FT8xx in Sleep (clk off) */
+#define EVE_PWRDOWN 0x50 /* place FT8xx in Power Down (core off) */
+#define EVE_CLKEXT 0x44 /* select external clock source */
+#define EVE_CLKINT 0x48 /* select internal clock source */
+#define EVE_CORERST 0x68 /* reset core - all registers default and processors reset */
+#define EVE_CLK48M 0x62 /* select 48MHz PLL output */
+#define EVE_CLK36M 0x61 /* select 36MHz PLL output */
+
+
+/* defines used for graphics commands */
+#define EVE_NEVER 0UL
+#define EVE_LESS 1UL
+#define EVE_LEQUAL 2UL
+#define EVE_GREATER 3UL
+#define EVE_GEQUAL 4UL
+#define EVE_EQUAL 5UL
+#define EVE_NOTEQUAL 6UL
+#define EVE_ALWAYS 7UL
+
+
+/* Bitmap formats */
+#define EVE_ARGB1555 0UL
+#define EVE_L1 1UL
+#define EVE_L4 2UL
+#define EVE_L8 3UL
+#define EVE_RGB332 4UL
+#define EVE_ARGB2 5UL
+#define EVE_ARGB4 6UL
+#define EVE_RGB565 7UL
+#define EVE_PALETTED 8UL
+#define EVE_TEXT8X8 9UL
+#define EVE_TEXTVGA 10UL
+#define EVE_BARGRAPH 11UL
+
+
+/* Bitmap filter types */
+#define EVE_NEAREST 0UL
+#define EVE_BILINEAR 1UL
+
+
+/* Bitmap wrap types */
+#define EVE_BORDER 0UL
+#define EVE_REPEAT 1UL
+
+
+/* Stencil defines */
+#define EVE_KEEP 1UL
+#define EVE_REPLACE 2UL
+#define EVE_INCR 3UL
+#define EVE_DECR 4UL
+#define EVE_INVERT 5UL
+
+
+/* Graphics display list swap defines */
+#define EVE_DLSWAP_DONE 0UL
+#define EVE_DLSWAP_LINE 1UL
+#define EVE_DLSWAP_FRAME 2UL
+
+
+/* Interrupt bits */
+#define EVE_INT_SWAP 0x01
+#define EVE_INT_TOUCH 0x02
+#define EVE_INT_TAG 0x04
+#define EVE_INT_SOUND 0x08
+#define EVE_INT_PLAYBACK 0x10
+#define EVE_INT_CMDEMPTY 0x20
+#define EVE_INT_CMDFLAG 0x40
+#define EVE_INT_CONVCOMPLETE 0x80
+
+
+/* Touch mode */
+#define EVE_TMODE_OFF 0
+#define EVE_TMODE_ONESHOT 1
+#define EVE_TMODE_FRAME 2
+#define EVE_TMODE_CONTINUOUS 3
+
+
+/* Alpha blending */
+#define EVE_ZERO 0UL
+#define EVE_ONE 1UL
+#define EVE_SRC_ALPHA 2UL
+#define EVE_DST_ALPHA 3UL
+#define EVE_ONE_MINUS_SRC_ALPHA 4UL
+#define EVE_ONE_MINUS_DST_ALPHA 5UL
+
+
+/* Graphics primitives */
+#define EVE_BITMAPS 1UL
+#define EVE_POINTS 2UL
+#define EVE_LINES 3UL
+#define EVE_LINE_STRIP 4UL
+#define EVE_EDGE_STRIP_R 5UL
+#define EVE_EDGE_STRIP_L 6UL
+#define EVE_EDGE_STRIP_A 7UL
+#define EVE_EDGE_STRIP_B 8UL
+#define EVE_RECTS 9UL
+
+
+/* Widget command */
+#define EVE_OPT_MONO 1
+#define EVE_OPT_NODL 2
+#define EVE_OPT_FLAT 256
+#define EVE_OPT_CENTERX 512
+#define EVE_OPT_CENTERY 1024
+#define EVE_OPT_CENTER (EVE_OPT_CENTERX | EVE_OPT_CENTERY)
+#define EVE_OPT_NOBACK 4096
+#define EVE_OPT_NOTICKS 8192
+#define EVE_OPT_NOHM 16384
+#define EVE_OPT_NOPOINTER 16384
+#define EVE_OPT_NOSECS 32768
+#define EVE_OPT_NOHANDS 49152
+#define EVE_OPT_RIGHTX 2048
+#define EVE_OPT_SIGNED 256
+
+
+/* Defines related to inbuilt font */
+#define EVE_NUMCHAR_PERFONT (128L) /* number of font characters per bitmap handle */
+#define EVE_FONT_TABLE_SIZE (148L) /* size of the font table - utilized for loopup by the graphics engine */
+#define EVE_FONT_TABLE_POINTER (0xFFFFCUL) /* pointer to the inbuilt font tables starting from bitmap handle 16 */
+
+
+/* Audio sample type defines */
+#define EVE_LINEAR_SAMPLES 0UL /* 8bit signed samples */
+#define EVE_ULAW_SAMPLES 1UL /* 8bit ulaw samples */
+#define EVE_ADPCM_SAMPLES 2UL /* 4bit ima adpcm samples */
+
+
+/* Synthesized sound */
+#define EVE_SILENCE 0x00
+#define EVE_SQUAREWAVE 0x01
+#define EVE_SINEWAVE 0x02
+#define EVE_SAWTOOTH 0x03
+#define EVE_TRIANGLE 0x04
+#define EVE_BEEPING 0x05
+#define EVE_ALARM 0x06
+#define EVE_WARBLE 0x07
+#define EVE_CAROUSEL 0x08
+#define EVE_PIPS(n) (0x0F + (n))
+#define EVE_HARP 0x40
+#define EVE_XYLOPHONE 0x41
+#define EVE_TUBA 0x42
+#define EVE_GLOCKENSPIEL 0x43
+#define EVE_ORGAN 0x44
+#define EVE_TRUMPET 0x45
+#define EVE_PIANO 0x46
+#define EVE_CHIMES 0x47
+#define EVE_MUSICBOX 0x48
+#define EVE_BELL 0x49
+#define EVE_CLICK 0x50
+#define EVE_SWITCH 0x51
+#define EVE_COWBELL 0x52
+#define EVE_NOTCH 0x53
+#define EVE_HIHAT 0x54
+#define EVE_KICKDRUM 0x55
+#define EVE_POP 0x56
+#define EVE_CLACK 0x57
+#define EVE_CHACK 0x58
+#define EVE_MUTE 0x60
+#define EVE_UNMUTE 0x61
+
+
+/* Synthesized sound frequencies, midi note */
+#define EVE_MIDI_A0 21
+#define EVE_MIDI_A_0 22
+#define EVE_MIDI_B0 23
+#define EVE_MIDI_C1 24
+#define EVE_MIDI_C_1 25
+#define EVE_MIDI_D1 26
+#define EVE_MIDI_D_1 27
+#define EVE_MIDI_E1 28
+#define EVE_MIDI_F1 29
+#define EVE_MIDI_F_1 30
+#define EVE_MIDI_G1 31
+#define EVE_MIDI_G_1 32
+#define EVE_MIDI_A1 33
+#define EVE_MIDI_A_1 34
+#define EVE_MIDI_B1 35
+#define EVE_MIDI_C2 36
+#define EVE_MIDI_C_2 37
+#define EVE_MIDI_D2 38
+#define EVE_MIDI_D_2 39
+#define EVE_MIDI_E2 40
+#define EVE_MIDI_F2 41
+#define EVE_MIDI_F_2 42
+#define EVE_MIDI_G2 43
+#define EVE_MIDI_G_2 44
+#define EVE_MIDI_A2 45
+#define EVE_MIDI_A_2 46
+#define EVE_MIDI_B2 47
+#define EVE_MIDI_C3 48
+#define EVE_MIDI_C_3 49
+#define EVE_MIDI_D3 50
+#define EVE_MIDI_D_3 51
+#define EVE_MIDI_E3 52
+#define EVE_MIDI_F3 53
+#define EVE_MIDI_F_3 54
+#define EVE_MIDI_G3 55
+#define EVE_MIDI_G_3 56
+#define EVE_MIDI_A3 57
+#define EVE_MIDI_A_3 58
+#define EVE_MIDI_B3 59
+#define EVE_MIDI_C4 60
+#define EVE_MIDI_C_4 61
+#define EVE_MIDI_D4 62
+#define EVE_MIDI_D_4 63
+#define EVE_MIDI_E4 64
+#define EVE_MIDI_F4 65
+#define EVE_MIDI_F_4 66
+#define EVE_MIDI_G4 67
+#define EVE_MIDI_G_4 68
+#define EVE_MIDI_A4 69
+#define EVE_MIDI_A_4 70
+#define EVE_MIDI_B4 71
+#define EVE_MIDI_C5 72
+#define EVE_MIDI_C_5 73
+#define EVE_MIDI_D5 74
+#define EVE_MIDI_D_5 75
+#define EVE_MIDI_E5 76
+#define EVE_MIDI_F5 77
+#define EVE_MIDI_F_5 78
+#define EVE_MIDI_G5 79
+#define EVE_MIDI_G_5 80
+#define EVE_MIDI_A5 81
+#define EVE_MIDI_A_5 82
+#define EVE_MIDI_B5 83
+#define EVE_MIDI_C6 84
+#define EVE_MIDI_C_6 85
+#define EVE_MIDI_D6 86
+#define EVE_MIDI_D_6 87
+#define EVE_MIDI_E6 88
+#define EVE_MIDI_F6 89
+#define EVE_MIDI_F_6 90
+#define EVE_MIDI_G6 91
+#define EVE_MIDI_G_6 92
+#define EVE_MIDI_A6 93
+#define EVE_MIDI_A_6 94
+#define EVE_MIDI_B6 95
+#define EVE_MIDI_C7 96
+#define EVE_MIDI_C_7 97
+#define EVE_MIDI_D7 98
+#define EVE_MIDI_D_7 99
+#define EVE_MIDI_E7 100
+#define EVE_MIDI_F7 101
+#define EVE_MIDI_F_7 102
+#define EVE_MIDI_G7 103
+#define EVE_MIDI_G_7 104
+#define EVE_MIDI_A7 105
+#define EVE_MIDI_A_7 106
+#define EVE_MIDI_B7 107
+#define EVE_MIDI_C8 108
+
+
+/* GPIO bits */
+#define EVE_GPIO0 0
+#define EVE_GPIO1 1 /* default gpio pin for audio shutdown, 1 - enable, 0 - disable */
+#define EVE_GPIO7 7 /* default gpio pin for display enable, 1 - enable, 0 - disable */
+
+
+/* Display rotation */
+#define EVE_DISPLAY_0 0 /* 0 degrees rotation */
+#define EVE_DISPLAY_180 1 /* 180 degrees rotation */
+
+
+/* commands common to EVE/EVE2/EVE3 */
+#define CMD_APPEND 0xFFFFFF1E
+#define CMD_BGCOLOR 0xFFFFFF09
+#define CMD_BUTTON 0xFFFFFF0D
+#define CMD_CALIBRATE 0xFFFFFF15
+#define CMD_CLOCK 0xFFFFFF14
+#define CMD_COLDSTART 0xFFFFFF32
+#define CMD_DIAL 0xFFFFFF2D
+#define CMD_DLSTART 0xFFFFFF00
+#define CMD_FGCOLOR 0xFFFFFF0A
+#define CMD_GAUGE 0xFFFFFF13
+#define CMD_GETMATRIX 0xFFFFFF33
+#define CMD_GETPROPS 0xFFFFFF25
+#define CMD_GETPTR 0xFFFFFF23
+#define CMD_GRADCOLOR 0xFFFFFF34
+#define CMD_GRADIENT 0xFFFFFF0B
+#define CMD_INFLATE 0xFFFFFF22
+#define CMD_INTERRUPT 0xFFFFFF02
+#define CMD_KEYS 0xFFFFFF0E
+#define CMD_LOADIDENTITY 0xFFFFFF26
+#define CMD_LOADIMAGE 0xFFFFFF24
+#define CMD_LOGO 0xFFFFFF31
+#define CMD_MEMCPY 0xFFFFFF1D
+#define CMD_MEMCRC 0xFFFFFF18
+#define CMD_MEMSET 0xFFFFFF1B
+#define CMD_MEMWRITE 0xFFFFFF1A
+#define CMD_MEMZERO 0xFFFFFF1C
+#define CMD_NUMBER 0xFFFFFF2E
+#define CMD_PROGRESS 0xFFFFFF0F
+#define CMD_REGREAD 0xFFFFFF19
+#define CMD_ROTATE 0xFFFFFF29
+#define CMD_SCALE 0xFFFFFF28
+#define CMD_SCREENSAVER 0xFFFFFF2F
+#define CMD_SCROLLBAR 0xFFFFFF11
+#define CMD_SETFONT 0xFFFFFF2B
+#define CMD_SETMATRIX 0xFFFFFF2A
+#define CMD_SKETCH 0xFFFFFF30
+#define CMD_SLIDER 0xFFFFFF10
+#define CMD_SNAPSHOT 0xFFFFFF1F
+#define CMD_SPINNER 0xFFFFFF16
+#define CMD_STOP 0xFFFFFF17
+#define CMD_SWAP 0xFFFFFF01
+#define CMD_TEXT 0xFFFFFF0C
+#define CMD_TOGGLE 0xFFFFFF12
+#define CMD_TRACK 0xFFFFFF2C
+#define CMD_TRANSLATE 0xFFFFFF27
+
+
+/* the following are undocumented commands that therefore should not be used */
+#if 0
+#define CMD_CRC 0xFFFFFF03
+#define CMD_HAMMERAUX 0xFFFFFF04
+#define CMD_MARCH 0xFFFFFF05
+#define CMD_IDCT 0xFFFFFF06
+#define CMD_EXECUTE 0xFFFFFF07
+#define CMD_GETPOINT 0xFFFFFF08
+#define CMD_TOUCH_TRANSFORM 0xFFFFFF20
+#endif
+
+
+/* FT8xx graphics engine specific macros useful for static display list generation */
+#define ALPHA_FUNC(func,ref) ((9UL<<24)|(((func)&7UL)<<8)|(((ref)&255UL)<<0))
+#define BEGIN(prim) ((31UL<<24)|(((prim)&15UL)<<0))
+#define BITMAP_HANDLE(handle) ((5UL<<24)|(((handle)&31UL)<<0))
+#define BITMAP_LAYOUT(format,linestride,height) ((7UL<<24)|(((format)&31UL)<<19)|(((linestride)&1023UL)<<9)|(((height)&511UL)<<0))
+#define BITMAP_SIZE(filter,wrapx,wrapy,width,height) ((8UL<<24)|(((filter)&1UL)<<20)|(((wrapx)&1UL)<<19)|(((wrapy)&1UL)<<18)|(((width)&511UL)<<9)|(((height)&511UL)<<0))
+#define BITMAP_TRANSFORM_A(a) ((21UL<<24)|(((a)&131071UL)<<0))
+#define BITMAP_TRANSFORM_B(b) ((22UL<<24)|(((b)&131071UL)<<0))
+#define BITMAP_TRANSFORM_C(c) ((23UL<<24)|(((c)&16777215UL)<<0))
+#define BITMAP_TRANSFORM_D(d) ((24UL<<24)|(((d)&131071UL)<<0))
+#define BITMAP_TRANSFORM_E(e) ((25UL<<24)|(((e)&131071UL)<<0))
+#define BITMAP_TRANSFORM_F(f) ((26UL<<24)|(((f)&16777215UL)<<0))
+#define BLEND_FUNC(src,dst) ((11UL<<24)|(((src)&7UL)<<3)|(((dst)&7UL)<<0))
+#define CALL(dest) ((29UL<<24)|(((dest)&65535UL)<<0))
+#define CELL(cell) ((6UL<<24)|(((cell)&127UL)<<0))
+#define CLEAR(c,s,t) ((38UL<<24)|(((c)&1UL)<<2)|(((s)&1UL)<<1)|(((t)&1UL)<<0))
+#define CLEAR_COLOR_A(alpha) ((15UL<<24)|(((alpha)&255UL)<<0))
+#define CLEAR_COLOR_RGB(red,green,blue) ((2UL<<24)|(((red)&255UL)<<16)|(((green)&255UL)<<8)|(((blue)&255UL)<<0))
+#define CLEAR_STENCIL(s) ((17UL<<24)|(((s)&255UL)<<0))
+#define CLEAR_TAG(s) ((18UL<<24)|(((s)&255UL)<<0))
+#define COLOR_A(alpha) ((16UL<<24)|(((alpha)&255UL)<<0))
+#define COLOR_MASK(r,g,b,a) ((32UL<<24)|(((r)&1UL)<<3)|(((g)&1UL)<<2)|(((b)&1UL)<<1)|(((a)&1UL)<<0))
+#define COLOR_RGB(red,green,blue) ((4UL<<24)|(((red)&255UL)<<16)|(((green)&255UL)<<8)|(((blue)&255UL)<<0))
+#define DISPLAY() ((0UL<<24))
+#define END() ((33UL<<24))
+#define JUMP(dest) ((30UL<<24)|(((dest)&65535UL)<<0))
+#define LINE_WIDTH(width) ((14UL<<24)|(((width)&4095UL)<<0))
+#define MACRO(m) ((37UL<<24)|(((m)&1UL)<<0))
+#define POINT_SIZE(size) ((13UL<<24)|(((size)&8191UL)<<0))
+#define RESTORE_CONTEXT() ((35UL<<24))
+#define RETURN() ((36UL<<24))
+#define SAVE_CONTEXT() ((34UL<<24))
+#define STENCIL_FUNC(func,ref,mask) ((10UL<<24)|(((func)&7UL)<<16)|(((ref)&255UL)<<8)|(((mask)&255UL)<<0))
+#define STENCIL_MASK(mask) ((19UL<<24)|(((mask)&255UL)<<0))
+#define STENCIL_OP(sfail,spass) ((12UL<<24)|(((sfail)&7UL)<<3)|(((spass)&7UL)<<0))
+#define TAG(s) ((3UL<<24)|(((s)&255UL)<<0))
+#define TAG_MASK(mask) ((20UL<<24)|(((mask)&1UL)<<0))
+#define VERTEX2F(x,y) ((1UL<<30)|(((x)&32767UL)<<15)|(((y)&32767UL)<<0))
+#define VERTEX2II(x,y,handle,cell) ((2UL<<30)|(((x)&511UL)<<21)|(((y)&511UL)<<12)|(((handle)&31UL)<<7)|(((cell)&127UL)<<0))
+
+
+/* ----------------- BT81x exclusive definitions -----------------*/
+#if defined (BT81X_ENABLE)
+
+#define EVE_GLFORMAT 31UL /* used with BITMAP_LAYOUT to indicate bitmap-format is specified by BITMAP_EXT_FORMAT */
+
+#define DL_BITMAP_EXT_FORMAT 0x2E000000 /* requires OR'd arguments */
+
+/* extended Bitmap formats */
+#define EVE_COMPRESSED_RGBA_ASTC_4x4_KHR 37808UL
+#define EVE_COMPRESSED_RGBA_ASTC_5x4_KHR 37809UL
+#define EVE_COMPRESSED_RGBA_ASTC_5x5_KHR 37810UL
+#define EVE_COMPRESSED_RGBA_ASTC_6x5_KHR 37811UL
+#define EVE_COMPRESSED_RGBA_ASTC_6x6_KHR 37812UL
+#define EVE_COMPRESSED_RGBA_ASTC_8x5_KHR 37813UL
+#define EVE_COMPRESSED_RGBA_ASTC_8x6_KHR 37814UL
+#define EVE_COMPRESSED_RGBA_ASTC_8x8_KHR 37815UL
+#define EVE_COMPRESSED_RGBA_ASTC_10x5_KHR 37816UL
+#define EVE_COMPRESSED_RGBA_ASTC_10x6_KHR 37817UL
+#define EVE_COMPRESSED_RGBA_ASTC_10x8_KHR 37818UL
+#define EVE_COMPRESSED_RGBA_ASTC_10x10_KHR 37819UL
+#define EVE_COMPRESSED_RGBA_ASTC_12x10_KHR 37820UL
+#define EVE_COMPRESSED_RGBA_ASTC_12x12_KHR 37821UL
+
+
+#define EVE_RAM_ERR_REPORT 0x309800UL /* max 128 bytes null terminated string */
+#define EVE_RAM_FLASH 0x800000UL
+#define EVE_RAM_FLASH_POSTBLOB 0x801000UL
+
+#define EVE_OPT_FLASH 64UL
+#define EVE_OPT_FORMAT 4096UL
+#define EVE_OPT_FILL 8192UL
+
+
+/* additional commands for BT81x */
+#define CMD_BITMAP_TRANSFORM 0xFFFFFF21
+#define CMD_SYNC 0xFFFFFF42 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_SYNC) */
+#define CMD_FLASHERASE 0xFFFFFF44 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHERASE) */
+#define CMD_FLASHWRITE 0xFFFFFF45
+#define CMD_FLASHREAD 0xFFFFFF46
+#define CMD_FLASHUPDATE 0xFFFFFF47
+#define CMD_FLASHDETACH 0xFFFFFF48 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHDETACH) */
+#define CMD_FLASHATTACH 0xFFFFFF49 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHATTACH) */
+#define CMD_FLASHFAST 0xFFFFFF4A
+#define CMD_FLASHSPIDESEL 0xFFFFFF4B /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHSPIDESEL) */
+#define CMD_FLASHSPITX 0xFFFFFF4C
+#define CMD_FLASHSPIRX 0xFFFFFF4D
+#define CMD_FLASHSOURCE 0xFFFFFF4E
+#define CMD_CLEARCACHE 0xFFFFFF4F /* does not need a dedicated function, just use EVE_cmd_dl(CMD_CLEARCACHE) */
+#define CMD_INFLATE2 0xFFFFFF50
+#define CMD_ROTATEAROUND 0xFFFFFF51
+#define CMD_RESETFONTS 0xFFFFFF52 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_RESETFONTS) */
+#define CMD_ANIMSTART 0xFFFFFF53
+#define CMD_ANIMSTOP 0xFFFFFF54
+#define CMD_ANIMXY 0xFFFFFF55
+#define CMD_ANIMDRAW 0xFFFFFF56
+#define CMD_GRADIENTA 0xFFFFFF57
+#define CMD_FILLWIDTH 0xFFFFFF58
+#define CMD_APPENDF 0xFFFFFF59
+#define CMD_ANIMFRAME 0xFFFFFF5A
+#define CMD_VIDEOSTARTF 0xFFFFFF5F /* does not need a dedicated function, just use EVE_cmd_dl(CMD_VIDEOSTARTF) */
+
+#if 0
+/* some undocumented commands for BT81x */
+#define CMD_NOP 0xFFFFFF5B
+#define CMD_SHA1 0xFFFFFF5C
+#define CMD_HMAC 0xFFFFFF5D
+#define CMD_LAST_ 0xFFFFFF5E
+
+#endif
+
+
+/* additional registers for BT81x */
+#define REG_ADAPTIVE_FRAMERATE 0x30257cUL
+#define REG_PLAYBACK_PAUSE 0x3025ecUL
+#define REG_FLASH_STATUS 0x3025f0UL
+#define REG_FLASH_SIZE 0x309024UL
+#define REG_PLAY_CONTROL 0x30914eUL
+#define REG_COPRO_PATCH_DTR 0x309162UL
+
+
+/* BT81x graphics engine specific macros */
+#define BITMAP_EXT_FORMAT(format) ((46UL<<24)|(((format)&65535UL)<<0))
+#define BITMAP_SWIZZLE(r,g,b,a) ((47UL<<24)|(((r)&7UL)<<9)|(((g)&7UL)<<6)|(((b)&7UL)<<3)|(((a)&7UL)<<0))
+#define BITMAP_SOURCE2(flash_or_ram, addr) ((1UL<<24)|((flash_or_ram) << 23)|(((addr)&8388607UL)<<0))
+#define INT_FRR() ((48UL<<24))
+
+#undef BITMAP_TRANSFORM_A
+#undef BITMAP_TRANSFORM_B
+#undef BITMAP_TRANSFORM_D
+#undef BITMAP_TRANSFORM_E
+
+#define BITMAP_TRANSFORM_A_EXT(p,v) ((21UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
+#define BITMAP_TRANSFORM_B_EXT(p,v) ((22UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
+#define BITMAP_TRANSFORM_D_EXT(p,v) ((24UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
+#define BITMAP_TRANSFORM_E_EXT(p,v) ((25UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
+
+#define BITMAP_TRANSFORM_A(a) BITMAP_TRANSFORM_A_EXT(0,a)
+#define BITMAP_TRANSFORM_B(b) BITMAP_TRANSFORM_B_EXT(0,b)
+#define BITMAP_TRANSFORM_D(d) BITMAP_TRANSFORM_D_EXT(0,d)
+#define BITMAP_TRANSFORM_E(e) BITMAP_TRANSFORM_E_EXT(0,e)
+
+#endif
+
+/* ----------------- FT81x / BT81x exclusive definitions -----------------*/
+#if defined (FT81X_ENABLE)
+
+
+/* Host commands */
+#define EVE_CLKSEL 0x61 /* configure system clock */
+#define EVE_RST_PULSE 0x68 /* reset core - all registers default and processors reset */
+#define EVE_PINDRIVE 0x70 /* setup drive strength for various pins */
+#define EVE_PIN_PD_STATE 0x71 /* setup how pins behave during power down */
+
+
+/* Memory definitions */
+#define EVE_RAM_G 0x000000UL
+#define EVE_ROM_CHIPID 0x0C0000UL
+#define EVE_ROM_FONT 0x1E0000UL
+#define EVE_ROM_FONT_ADDR 0x2FFFFCUL
+#define EVE_RAM_DL 0x300000UL
+#define EVE_RAM_REG 0x302000UL
+#define EVE_RAM_CMD 0x308000UL
+
+
+/* Memory buffer sizes */
+#define EVE_RAM_G_SIZE 1024*1024L
+#define EVE_CMDFIFO_SIZE 4*1024L
+#define EVE_RAM_DL_SIZE 8*1024L
+
+
+/* various additional defines for FT81x */
+#define EVE_ADC_DIFFERENTIAL 1UL
+#define EVE_ADC_SINGLE_ENDED 0UL
+
+#define EVE_INT_G8 18UL
+#define EVE_INT_L8C 12UL
+#define EVE_INT_VGA 13UL
+
+#define EVE_OPT_MEDIAFIFO 16UL
+#define EVE_OPT_FULLSCREEN 8UL
+#define EVE_OPT_NOTEAR 4UL
+#define EVE_OPT_SOUND 32UL
+
+#define EVE_PALETTED565 14UL
+#define EVE_PALETTED4444 15UL
+#define EVE_PALETTED8 16UL
+#define EVE_L2 17UL
+
+
+/* additional commands for FT81x */
+#define CMD_MEDIAFIFO 0xFFFFFF39
+#define CMD_PLAYVIDEO 0xFFFFFF3A
+#define CMD_ROMFONT 0xFFFFFF3F
+#define CMD_SETBASE 0xFFFFFF38
+#define CMD_SETBITMAP 0xFFFFFF43
+#define CMD_SETFONT2 0xFFFFFF3B
+#define CMD_SETROTATE 0xFFFFFF36
+#define CMD_SETSCRATCH 0xFFFFFF3C
+#define CMD_SNAPSHOT2 0xFFFFFF37
+#define CMD_VIDEOFRAME 0xFFFFFF41
+#define CMD_VIDEOSTART 0xFFFFFF40
+
+
+/* the following are undocumented commands that therefore should not be used */
+#if 0
+#define CMD_CSKETCH 0xFFFFFF35
+#define CMD_INT_RAMSHARED 0xFFFFFF3D
+#define CMD_INT_SWLOADIMAGE 0xFFFFFF3E
+#endif
+
+
+/* Register definitions */
+#define REG_ANA_COMP 0x302184UL /* only listed in datasheet */
+#define REG_BIST_EN 0x302174UL /* only listed in datasheet */
+#define REG_CLOCK 0x302008UL
+#define REG_CMDB_SPACE 0x302574UL
+#define REG_CMDB_WRITE 0x302578UL
+#define REG_CMD_DL 0x302100UL
+#define REG_CMD_READ 0x3020f8UL
+#define REG_CMD_WRITE 0x3020fcUL
+#define REG_CPURESET 0x302020UL
+#define REG_CSPREAD 0x302068UL
+#define REG_CTOUCH_EXTENDED 0x302108UL
+#define REG_CTOUCH_TOUCH0_XY 0x302124UL /* only listed in datasheet */
+#define REG_CTOUCH_TOUCH4_X 0x30216cUL
+#define REG_CTOUCH_TOUCH4_Y 0x302120UL
+#define REG_CTOUCH_TOUCH1_XY 0x30211cUL
+#define REG_CTOUCH_TOUCH2_XY 0x30218cUL
+#define REG_CTOUCH_TOUCH3_XY 0x302190UL
+#define REG_TOUCH_CONFIG 0x302168UL
+#define REG_DATESTAMP 0x302564UL /* only listed in datasheet */
+#define REG_DITHER 0x302060UL
+#define REG_DLSWAP 0x302054UL
+#define REG_FRAMES 0x302004UL
+#define REG_FREQUENCY 0x30200cUL
+#define REG_GPIO 0x302094UL
+#define REG_GPIOX 0x30209cUL
+#define REG_GPIOX_DIR 0x302098UL
+#define REG_GPIO_DIR 0x302090UL
+#define REG_HCYCLE 0x30202cUL
+#define REG_HOFFSET 0x302030UL
+#define REG_HSIZE 0x302034UL
+#define REG_HSYNC0 0x302038UL
+#define REG_HSYNC1 0x30203cUL
+#define REG_ID 0x302000UL
+#define REG_INT_EN 0x3020acUL
+#define REG_INT_FLAGS 0x3020a8UL
+#define REG_INT_MASK 0x3020b0UL
+#define REG_MACRO_0 0x3020d8UL
+#define REG_MACRO_1 0x3020dcUL
+#define REG_MEDIAFIFO_READ 0x309014UL /* only listed in programmers guide */
+#define REG_MEDIAFIFO_WRITE 0x309018UL /* only listed in programmers guide */
+#define REG_OUTBITS 0x30205cUL
+#define REG_PCLK 0x302070UL
+#define REG_PCLK_POL 0x30206cUL
+#define REG_PLAY 0x30208cUL
+#define REG_PLAYBACK_FORMAT 0x3020c4UL
+#define REG_PLAYBACK_FREQ 0x3020c0UL
+#define REG_PLAYBACK_LENGTH 0x3020b8UL
+#define REG_PLAYBACK_LOOP 0x3020c8UL
+#define REG_PLAYBACK_PLAY 0x3020ccUL
+#define REG_PLAYBACK_READPTR 0x3020bcUL
+#define REG_PLAYBACK_START 0x3020b4UL
+#define REG_PWM_DUTY 0x3020d4UL
+#define REG_PWM_HZ 0x3020d0UL
+#define REG_RENDERMODE 0x302010UL /* only listed in datasheet */
+#define REG_ROTATE 0x302058UL
+#define REG_SNAPFORMAT 0x30201cUL /* only listed in datasheet */
+#define REG_SNAPSHOT 0x302018UL /* only listed in datasheet */
+#define REG_SNAPY 0x302014UL /* only listed in datasheet */
+#define REG_SOUND 0x302088UL
+#define REG_SPI_WIDTH 0x302188UL /* listed with false offset in programmers guide V1.1 */
+#define REG_SWIZZLE 0x302064UL
+#define REG_TAG 0x30207cUL
+#define REG_TAG_X 0x302074UL
+#define REG_TAG_Y 0x302078UL
+#define REG_TAP_CRC 0x302024UL /* only listed in datasheet */
+#define REG_TAP_MASK 0x302028UL /* only listed in datasheet */
+#define REG_TOUCH_ADC_MODE 0x302108UL
+#define REG_TOUCH_CHARGE 0x30210cUL
+#define REG_TOUCH_DIRECT_XY 0x30218cUL
+#define REG_TOUCH_DIRECT_Z1Z2 0x302190UL
+#define REG_TOUCH_MODE 0x302104UL
+#define REG_TOUCH_OVERSAMPLE 0x302114UL
+#define REG_TOUCH_RAW_XY 0x30211cUL
+#define REG_TOUCH_RZ 0x302120UL
+#define REG_TOUCH_RZTHRESH 0x302118UL
+#define REG_TOUCH_SCREEN_XY 0x302124UL
+#define REG_TOUCH_SETTLE 0x302110UL
+#define REG_TOUCH_TAG 0x30212cUL
+#define REG_TOUCH_TAG1 0x302134UL /* only listed in datasheet */
+#define REG_TOUCH_TAG1_XY 0x302130UL /* only listed in datasheet */
+#define REG_TOUCH_TAG2 0x30213cUL /* only listed in datasheet */
+#define REG_TOUCH_TAG2_XY 0x302138UL /* only listed in datasheet */
+#define REG_TOUCH_TAG3 0x302144UL /* only listed in datasheet */
+#define REG_TOUCH_TAG3_XY 0x302140UL /* only listed in datasheet */
+#define REG_TOUCH_TAG4 0x30214cUL /* only listed in datasheet */
+#define REG_TOUCH_TAG4_XY 0x302148UL /* only listed in datasheet */
+#define REG_TOUCH_TAG_XY 0x302128UL
+#define REG_TOUCH_TRANSFORM_A 0x302150UL
+#define REG_TOUCH_TRANSFORM_B 0x302154UL
+#define REG_TOUCH_TRANSFORM_C 0x302158UL
+#define REG_TOUCH_TRANSFORM_D 0x30215cUL
+#define REG_TOUCH_TRANSFORM_E 0x302160UL
+#define REG_TOUCH_TRANSFORM_F 0x302164UL
+#define REG_TRACKER 0x309000UL /* only listed in programmers guide */
+#define REG_TRACKER_1 0x309004UL /* only listed in programmers guide */
+#define REG_TRACKER_2 0x309008UL /* only listed in programmers guide */
+#define REG_TRACKER_3 0x30900cUL /* only listed in programmers guide */
+#define REG_TRACKER_4 0x309010UL /* only listed in programmers guide */
+#define REG_TRIM 0x302180UL
+#define REG_VCYCLE 0x302040UL
+#define REG_VOFFSET 0x302044UL
+#define REG_VOL_PB 0x302080UL
+#define REG_VOL_SOUND 0x302084UL
+#define REG_VSIZE 0x302048UL
+#define REG_VSYNC0 0x30204cUL
+#define REG_VSYNC1 0x302050UL
+
+#if 0
+#define REG_BUSYBITS 0x3020e8UL /* only listed as "reserved" in datasheet */
+#define REG_CRC 0x302178UL /* only listed as "reserved" in datasheet */
+#define REG_SPI_EARLY_TX 0x30217cUL /* only listed as "reserved" in datasheet */
+#define REG_ROMSUB_SEL 0x3020f0UL /* only listed as "reserved" in datasheet */
+#define REG_TOUCH_FAULT 0x302170UL /* only listed as "reserved" in datasheet */
+#endif
+
+
+/* FT81x graphics engine specific macros useful for static display list generation */
+
+/* beware, these are different to FTDIs implementation as these take the original values as parameters and not only the upper bits */
+#define BITMAP_LAYOUT_H(linestride,height) ((40UL<<24)|((((linestride&0xC00)>>10)&3UL)<<2)|((((height&0x600)>>9)&3UL)<<0))
+#define BITMAP_SIZE_H(width,height) ((41UL<<24)|((((width&0x600)>>9)&3UL)<<2)|((((height&0x600)>>9)&3UL)<<0))
+
+#define BITMAP_SOURCE(addr) ((1UL<<24)|(((addr)&4194303UL)<<0))
+#define NOP() ((45UL<<24))
+#define PALETTE_SOURCE(addr) ((42UL<<24)|(((addr)&4194303UL)<<0))
+#define SCISSOR_SIZE(width,height) ((28UL<<24)|(((width)&4095UL)<<12)|(((height)&4095UL)<<0))
+#define SCISSOR_XY(x,y) ((27UL<<24)|(((x)&2047UL)<<11)|(((y)&2047UL)<<0))
+#define VERTEX_FORMAT(frac) ((39UL<<24)|(((frac)&7UL)<<0))
+#define VERTEX_TRANSLATE_X(x) ((43UL<<24)|(((x)&131071UL)<<0))
+#define VERTEX_TRANSLATE_Y(y) ((44UL<<24)|(((y)&131071UL)<<0))
+
+
+
+/* ----------------- FT80x exclusive definitions -----------------*/
+#else
+
+/* Memory definitions */
+#define EVE_RAM_G 0x000000UL
+#define EVE_ROM_CHIPID 0x0C0000UL
+#define EVE_ROM_FONT 0x0BB23CUL
+#define EVE_ROM_FONT_ADDR 0x0FFFFCUL
+#define EVE_RAM_DL 0x100000UL
+#define EVE_RAM_PAL 0x102000UL
+#define EVE_RAM_CMD 0x108000UL
+#define EVE_RAM_SCREENSHOT 0x1C2000UL
+
+
+/* Memory buffer sizes */
+#define EVE_RAM_G_SIZE 256*1024L
+#define EVE_CMDFIFO_SIZE 4*1024L
+#define EVE_RAM_DL_SIZE 8*1024L
+#define EVE_RAM_PAL_SIZE 1*1024L
+
+
+/* Register definitions */
+#define REG_ID 0x102400UL
+#define REG_FRAMES 0x102404UL
+#define REG_CLOCK 0x102408UL
+#define REG_FREQUENCY 0x10240CUL
+#define REG_SCREENSHOT_EN 0x102410UL
+#define REG_SCREENSHOT_Y 0x102414UL
+#define REG_SCREENSHOT_START 0x102418UL
+#define REG_CPURESET 0x10241CUL
+#define REG_TAP_CRC 0x102420UL
+#define REG_TAP_MASK 0x102424UL
+#define REG_HCYCLE 0x102428UL
+#define REG_HOFFSET 0x10242CUL
+#define REG_HSIZE 0x102430UL
+#define REG_HSYNC0 0x102434UL
+#define REG_HSYNC1 0x102438UL
+#define REG_VCYCLE 0x10243CUL
+#define REG_VOFFSET 0x102440UL
+#define REG_VSIZE 0x102444UL
+#define REG_VSYNC0 0x102448UL
+#define REG_VSYNC1 0x10244CUL
+#define REG_DLSWAP 0x102450UL
+#define REG_ROTATE 0x102454UL
+#define REG_OUTBITS 0x102458UL
+#define REG_DITHER 0x10245CUL
+#define REG_SWIZZLE 0x102460UL
+#define REG_CSPREAD 0x102464UL
+#define REG_PCLK_POL 0x102468UL
+#define REG_PCLK 0x10246CUL
+#define REG_TAG_X 0x102470UL
+#define REG_TAG_Y 0x102474UL
+#define REG_TAG 0x102478UL
+#define REG_VOL_PB 0x10247CUL
+#define REG_VOL_SOUND 0x102480UL
+#define REG_SOUND 0x102484UL
+#define REG_PLAY 0x102488UL
+#define REG_GPIO_DIR 0x10248CUL
+#define REG_GPIO 0x102490UL
+#define REG_INT_FLAGS 0x102498UL
+#define REG_INT_EN 0x10249CUL
+#define REG_INT_MASK 0x1024A0UL
+#define REG_PLAYBACK_START 0x1024A4UL
+#define REG_PLAYBACK_LENGTH 0x1024A8UL
+#define REG_PLAYBACK_READPTR 0x1024ACUL
+#define REG_PLAYBACK_FREQ 0x1024B0UL
+#define REG_PLAYBACK_FORMAT 0x1024B4UL
+#define REG_PLAYBACK_LOOP 0x1024B8UL
+#define REG_PLAYBACK_PLAY 0x1024BCUL
+#define REG_PWM_HZ 0x1024C0UL
+#define REG_PWM_DUTY 0x1024C4UL
+#define REG_MACRO_0 0x1024C8UL
+#define REG_MACRO_1 0x1024CCUL
+#define REG_SCREENSHOT_BUSY 0x1024D8UL
+#define REG_CMD_READ 0x1024E4UL
+#define REG_CMD_WRITE 0x1024E8UL
+#define REG_CMD_DL 0x1024ECUL
+#define REG_TOUCH_MODE 0x1024F0UL
+#define REG_TOUCH_ADC_MODE 0x1024F4UL
+#define REG_TOUCH_CHARGE 0x1024F8UL
+#define REG_TOUCH_SETTLE 0x1024FCUL
+#define REG_TOUCH_OVERSAMPLE 0x102500UL
+#define REG_TOUCH_RZTHRESH 0x102504UL
+#define REG_TOUCH_RAW_XY 0x102508UL
+#define REG_TOUCH_RZ 0x10250CUL
+#define REG_TOUCH_SCREEN_XY 0x102510UL
+#define REG_TOUCH_TAG_XY 0x102514UL
+#define REG_TOUCH_TAG 0x102518UL
+#define REG_TOUCH_TRANSFORM_A 0x10251CUL
+#define REG_TOUCH_TRANSFORM_B 0x102520UL
+#define REG_TOUCH_TRANSFORM_C 0x102524UL
+#define REG_TOUCH_TRANSFORM_D 0x102528UL
+#define REG_TOUCH_TRANSFORM_E 0x10252CUL
+#define REG_TOUCH_TRANSFORM_F 0x102530UL
+#define REG_SCREENSHOT_READ 0x102554UL
+#define REG_TRIM 0x10256CUL
+#define REG_TOUCH_DIRECT_XY 0x102574UL
+#define REG_TOUCH_DIRECT_Z1Z2 0x102578UL
+#define REG_TRACKER 0x109000UL
+
+/* FT80x graphics engine specific macros useful for static display list generation */
+#define BITMAP_SOURCE(addr) ((1UL<<24)|(((addr)&1048575UL)<<0))
+#define SCISSOR_SIZE(width,height) ((28UL<<24)|(((width)&1023UL)<<10)|(((height)&1023UL)<<0))
+#define SCISSOR_XY(x,y) ((27UL<<24)|(((x)&511UL)<<9)|(((y)&511UL)<<0))
+
+#endif
+
+#endif /* EVE_H_ */
diff --git a/fw/fe310/eos/eve/eve_kbd.c b/fw/fe310/eos/eve/eve_kbd.c new file mode 100644 index 0000000..99210ce --- /dev/null +++ b/fw/fe310/eos/eve/eve_kbd.c @@ -0,0 +1,161 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" + +#define KBD_X 0 +#define KBD_Y 575 +#define KBD_W 480 +#define KBD_H 225 + +#define KEY_SPACERX 3 +#define KEY_SPACERY 5 +#define KEY_FONT 29 +#define MOD_FONT 21 + +#define KEY_BS 0x08 +#define KEY_RET 0x0a + +#define FLAG_SHIFT 0x01 +#define FLAG_CTRL 0x02 +#define FLAG_FN 0x04 + +#define TAG_SHIFT 0x11 +#define TAG_CTRL 0x12 +#define TAG_FN 0x13 + +void eve_kbd_init(EVEKbd *kbd, EVERect *g, uint32_t mem_addr, uint32_t *mem_next) { + uint16_t mem_size; + + if (g) { + kbd->g = *g; + } else { + kbd->g.x = KBD_X; + kbd->g.y = KBD_Y; + kbd->g.w = KBD_W; + kbd->g.h = KBD_H; + } + kbd->mem_addr = mem_addr; + kbd->key_modifier = 0; + kbd->key_count = 0; + kbd->key_down = 0; + kbd->putc = NULL; + kbd->param = NULL; + + kbd->active = 1; + eve_write16(REG_CMD_DL, 0); + eve_kbd_draw(kbd); + eve_cmd_exec(1); + mem_size = eve_read16(REG_CMD_DL); + eve_cmd(CMD_MEMCPY, "www", mem_addr, EVE_RAM_DL, mem_size); + eve_cmd_exec(1); + kbd->active = 0; + kbd->mem_size = mem_size; + + *mem_next = kbd->mem_addr + kbd->mem_size; +} + +void eve_kbd_set_handler(EVEKbd *kbd, eve_kbd_input_handler_t putc, void *param) { + kbd->putc = putc; + kbd->param = param; +} + +int eve_kbd_touch(EVEKbd *kbd, uint8_t tag0, int touch_idx) { + EVETouch *t; + uint16_t evt; + + t = eve_touch_evt(tag0, touch_idx, 1, 126, &evt); + if (t && evt) { + if (evt & EVE_TOUCH_ETYPE_TAG) { + uint8_t _tag = t->tag; + + if (_tag >= TAG_SHIFT && _tag <= TAG_FN) { + if (touch_idx == 0) { + uint8_t f = (1 << (_tag - TAG_SHIFT)); + + kbd->key_modifier = f; + kbd->key_modifier_sticky &= f; + kbd->key_modifier_lock &= f; + if (kbd->key_modifier_lock & f) { + kbd->key_modifier_lock &= ~f; + } else if (kbd->key_modifier_sticky & f) { + kbd->key_modifier_sticky &= ~f; + kbd->key_modifier_lock |= f; + } else { + kbd->key_modifier_sticky |= f; + } + } + } else { + kbd->key_count++; + kbd->key_down = _tag; + if (kbd->putc) { + int c = _tag; + + if ((kbd->key_modifier & FLAG_CTRL) && (_tag >= '?') && (_tag <= '_')) c = (_tag - '@') & 0x7f; + kbd->putc(kbd->param, c); + } + } + } + if (evt & EVE_TOUCH_ETYPE_TAG_UP) { + uint8_t _tag = t->tag_up; + + if (_tag >= TAG_SHIFT && _tag <= TAG_FN) { + if (touch_idx == 0) { + uint8_t f = (1 << (_tag - TAG_SHIFT)); + + if (!((kbd->key_modifier_lock | kbd->key_modifier_sticky) & f)) { + kbd->key_modifier &= ~f; + } + } + } else { + if (kbd->key_count) kbd->key_count--; + if (!kbd->key_count) kbd->key_down = 0; + if (kbd->key_modifier_sticky) { + if (touch_idx == 0) kbd->key_modifier &= ~kbd->key_modifier_sticky; + kbd->key_modifier_sticky = 0; + } + } + } + kbd->active = 1; + } else { + kbd->active = 0; + } + + return kbd->active; +} + +uint8_t eve_kbd_draw(EVEKbd *kbd) { + if (kbd->active) { + int x = kbd->g.x; + int y = kbd->g.y; + int w = kbd->g.w; + int row_h = kbd->g.h / 5; + int key_w = (w - 9 * KEY_SPACERX) / 10 + 1; + int mod_w = key_w + key_w / 2; + int key_h = row_h - KEY_SPACERY; + + eve_cmd_dl(SAVE_CONTEXT()); + eve_cmd(CMD_KEYS, "hhhhhhs", x, y + row_h * 0, w, key_h, KEY_FONT, kbd->key_down, kbd->key_modifier & (FLAG_FN | FLAG_SHIFT) ? "!@#$%^&*()" : (kbd->key_modifier & FLAG_CTRL ? " @[\\]^_? " : "1234567890")); + eve_cmd(CMD_KEYS, "hhhhhhs", x, y + row_h * 1, w, key_h, KEY_FONT, kbd->key_down, kbd->key_modifier & FLAG_FN ? "-_=+[]{}\\|" : kbd->key_modifier & (FLAG_SHIFT | FLAG_CTRL) ? "QWERTYUIOP" : "qwertyuiop"); + eve_cmd(CMD_KEYS, "hhhhhhs", x + key_w / 2, y + row_h * 2, w - key_w, key_h, KEY_FONT, kbd->key_down, kbd->key_modifier & FLAG_FN ? "`~ ;:'\"" : kbd->key_modifier & (FLAG_SHIFT | FLAG_CTRL) ? "ASDFGHJKL" : "asdfghjkl"); + eve_cmd(CMD_KEYS, "hhhhhhs", x + mod_w + KEY_SPACERX, y + row_h * 3, w - 2 * (mod_w + KEY_SPACERX), key_h, KEY_FONT, kbd->key_down, kbd->key_modifier & FLAG_FN ? " ,.<>/?" : kbd->key_modifier & (FLAG_SHIFT | FLAG_CTRL) ? "ZXCVBNM" : "zxcvbnm"); + eve_cmd_dl(TAG(TAG_SHIFT)); + eve_cmd(CMD_BUTTON, "hhhhhhs", x, y + row_h * 3, mod_w, key_h, MOD_FONT, kbd->key_modifier & FLAG_SHIFT ? EVE_OPT_FLAT : 0, "shift"); + eve_cmd_dl(TAG(KEY_BS)); + eve_cmd(CMD_BUTTON, "hhhhhhs", x + w - mod_w, y + row_h * 3, mod_w, key_h, MOD_FONT, kbd->key_down == KEY_BS ? EVE_OPT_FLAT : 0, "del"); + eve_cmd_dl(TAG(TAG_FN)); + eve_cmd(CMD_BUTTON, "hhhhhhs", x, y + row_h * 4, mod_w, key_h, MOD_FONT, kbd->key_modifier & FLAG_FN ? EVE_OPT_FLAT : 0, "fn"); + eve_cmd_dl(TAG(TAG_CTRL)); + eve_cmd(CMD_BUTTON, "hhhhhhs", x + mod_w + KEY_SPACERX, y + row_h * 4, mod_w, key_h, MOD_FONT, kbd->key_modifier & FLAG_CTRL ? EVE_OPT_FLAT : 0, "ctrl"); + eve_cmd_dl(TAG(' ')); + eve_cmd(CMD_BUTTON, "hhhhhhs", x + 2 * (mod_w + KEY_SPACERX), y + row_h * 4, w - 3 * (mod_w + KEY_SPACERX), key_h, MOD_FONT, kbd->key_down == ' ' ? EVE_OPT_FLAT : 0, ""); + eve_cmd_dl(TAG(KEY_RET)); + eve_cmd(CMD_BUTTON, "hhhhhhs", x + w - mod_w, y + row_h * 4, mod_w, key_h, MOD_FONT, kbd->key_down == KEY_RET ? EVE_OPT_FLAT : 0, "ret"); + eve_cmd_dl(RESTORE_CONTEXT()); + } else { + eve_cmd(CMD_APPEND, "ww", kbd->mem_addr, kbd->mem_size); + } + + return 0x80; +} diff --git a/fw/fe310/eos/eve/eve_kbd.h b/fw/fe310/eos/eve/eve_kbd.h new file mode 100644 index 0000000..b27f54d --- /dev/null +++ b/fw/fe310/eos/eve/eve_kbd.h @@ -0,0 +1,22 @@ +#include <stdint.h> + +typedef void (*eve_kbd_input_handler_t) (void *, int); + +typedef struct EVEKbd { + EVERect g; + uint32_t mem_addr; + uint16_t mem_size; + uint8_t key_count; + uint8_t key_down; + uint8_t key_modifier; + uint8_t key_modifier_sticky; + uint8_t key_modifier_lock; + char active; + eve_kbd_input_handler_t putc; + void *param; +} EVEKbd; + +void eve_kbd_init(EVEKbd *kbd, EVERect *g, uint32_t mem_addr, uint32_t *mem_next); +void eve_kbd_set_handler(EVEKbd *kbd, eve_kbd_input_handler_t putc, void *param); +int eve_kbd_touch(EVEKbd *kbd, uint8_t tag0, int touch_idx); +uint8_t eve_kbd_draw(EVEKbd *kbd); diff --git a/fw/fe310/eos/eve/eve_platform.c b/fw/fe310/eos/eve/eve_platform.c new file mode 100644 index 0000000..e64d326 --- /dev/null +++ b/fw/fe310/eos/eve/eve_platform.c @@ -0,0 +1,63 @@ +#include <stdlib.h> + +#include "platform.h" + +#include "eos.h" +#include "interrupt.h" +#include "event.h" +#include "eve.h" +#include "eve_platform.h" + +#include "irq_def.h" + +static void handle_time(unsigned char type) { + eos_spi_dev_start(EOS_DEV_DISP); + eve_handle_time(); + eos_spi_dev_stop(); +} + +static void handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + eos_spi_dev_start(EOS_DEV_DISP); + eve_handle_touch(); + eos_spi_dev_stop(); + + GPIO_REG(GPIO_LOW_IP) = (1 << EVE_PIN_INTR); + GPIO_REG(GPIO_LOW_IE) |= (1 << EVE_PIN_INTR); +} + +static void handle_intr(void) { + GPIO_REG(GPIO_LOW_IE) &= ~(1 << EVE_PIN_INTR); + eos_evtq_push_isr(EOS_EVT_UI | EVE_ETYPE_INTR, NULL, 0); + return; +} + +void eve_time_sleep(uint32_t ms) { + eos_time_sleep(ms); +} + +void eve_timer_set(uint32_t ms) { + eos_timer_set(ms, EOS_TIMER_ETYPE_UI); +} + +void eve_timer_clear(void) { + eos_timer_clear(EOS_TIMER_ETYPE_UI); +} + +uint64_t eve_time_get_tick(void) { + return eos_time_get_tick(); +} + +void eve_platform_init(void) { + eos_evtq_set_handler(EOS_EVT_UI, handle_evt); + eos_timer_set_handler(EOS_TIMER_ETYPE_UI, handle_time); + + GPIO_REG(GPIO_INPUT_EN) |= (1 << EVE_PIN_INTR); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << EVE_PIN_INTR); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << EVE_PIN_INTR); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << EVE_PIN_INTR); + + GPIO_REG(GPIO_LOW_IE) |= (1 << EVE_PIN_INTR); + eos_intr_set(INT_GPIO_BASE + EVE_PIN_INTR, IRQ_PRIORITY_UI, handle_intr); + + eos_spi_dev_set_div(EOS_DEV_DISP, 4); +} diff --git a/fw/fe310/eos/eve/eve_platform.h b/fw/fe310/eos/eve/eve_platform.h new file mode 100644 index 0000000..41ec6b4 --- /dev/null +++ b/fw/fe310/eos/eve/eve_platform.h @@ -0,0 +1,27 @@ +#include <stdint.h> + +#include "../spi.h" +#include "../timer.h" + +#define EVE_ETYPE_INTR 1 +#define EVE_PIN_INTR 0 + +#define EVE_RTC_FREQ EOS_TIMER_RTC_FREQ + +#define EVE_SPI_FLAG_BSWAP EOS_SPI_FLAG_BSWAP +#define EVE_SPI_FLAG_TX EOS_SPI_FLAG_TX + +#define eve_spi_cs_set eos_spi_cs_set +#define eve_spi_cs_clear eos_spi_cs_clear +#define eve_spi_flush eos_spi_flush +#define eve_spi_xchg8 eos_spi_xchg8 +#define eve_spi_xchg16 eos_spi_xchg16 +#define eve_spi_xchg24 eos_spi_xchg24 +#define eve_spi_xchg32 eos_spi_xchg32 + +void eve_time_sleep(uint32_t ms); +void eve_timer_set(uint32_t ms); +void eve_timer_clear(void); +uint64_t eve_time_get_tick(void); + +void eve_platform_init(void); diff --git a/fw/fe310/eos/eve/eve_text.c b/fw/fe310/eos/eve/eve_text.c new file mode 100644 index 0000000..2ad4f6f --- /dev/null +++ b/fw/fe310/eos/eve/eve_text.c @@ -0,0 +1,199 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_text.h" + +#define TEXT_ATTR 0x0A +#define TEXT_CRSR 0x02DB + +#define LINE_IDX_ADD(l1,l2,s) (((((l1) + (l2)) % (s)) + (s)) % (s)) +#define LINE_IDX_SUB(l1,l2,s) (((((l1) - (l2)) % (s)) + (s)) % (s)) + +#define LINE_IDX_LTE(l1,l2,s,h) (LINE_IDX_SUB(l2,l1,s) <= (s) - (h)) +#define LINE_IDX_DIFF(l1,l2,s) ((l1) > (l2) ? (l1) - (l2) : (s) + (l1) - (l2)) + +static void scroll1(EVEText *box) { + box->line0 = (box->line0 + 1) % box->line_size; + eve_cmd(CMD_MEMSET, "www", box->mem_addr + box->ch_idx, 0x0, box->w * 2); + eve_cmd_exec(1); + box->dirty = 1; +} + +void eve_text_init(EVEText *box, EVERect *g, uint16_t w, uint16_t h, uint8_t tag, uint16_t line_size, uint32_t mem_addr, uint32_t *mem_next) { + double scale_x, scale_y; + + if (g->w == 0) { + g->w = w * 8; + } + if (g->h == 0) { + g->h = h * 16; + } + + scale_x = (double)g->w / (w * 8); + scale_y = (double)g->h / (h * 16); + box->g = *g; + box->w = w; + box->h = h; + box->tag = tag; + box->transform_a = 256 / scale_x; + box->transform_e = 256 / scale_y; + box->ch_w = scale_x * 8; + box->ch_h = scale_y * 16; + box->dl_size = 17; + box->mem_addr = mem_addr; + box->line_size = line_size; + box->line0 = 0; + box->line_top = -1; + box->line_top0 = -1; + box->ch_idx = 0; + if (box->transform_a != 256) { + box->dl_size += 1; + } + if (box->transform_e != 256) { + box->dl_size += 1; + } + + eve_touch_set_opt(tag, EVE_TOUCH_OPT_TRACK); + + eve_cmd(CMD_MEMSET, "www", mem_addr, 0x0, box->w * 2 * box->line_size); + eve_cmd_exec(1); + + eve_text_update(box); + *mem_next = box->mem_addr + box->w * 2 * box->line_size + box->dl_size * 4; +} + +int eve_text_touch(EVEText *box, uint8_t tag0, int touch_idx) { + EVETouch *t; + uint16_t evt; + int ret = 0; + + t = eve_touch_evt(tag0, touch_idx, box->tag, 1, &evt); + if (t && evt) { + if ((evt & EVE_TOUCH_ETYPE_TRACK_START) && (box->line_top < 0)) { + box->line_top = box->line0; + box->line_top0 = box->line0; + } + if ((evt & EVE_TOUCH_ETYPE_TRACK) && (box->line_top0 >=0)) { + int line = LINE_IDX_ADD(box->line_top0, (t->y0 - t->y) / box->ch_h, box->line_size); + if (LINE_IDX_LTE(line, box->line0, box->line_size, box->h)) { + box->line_top = line; + box->dirty = 1; + } + } + if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) { + box->line_top0 = box->line_top; + } + ret = 1; + } else if (box->line_top >= 0) { + box->line_top = -1; + box->line_top0 = -1; + box->dirty = 1; + } + return ret; +} + +uint8_t eve_text_draw(EVEText *box) { + if (box->dirty) { + eve_text_update(box); + box->dirty = 0; + } + eve_cmd(CMD_APPEND, "ww", box->mem_addr + box->w * 2 * box->line_size, box->dl_size * 4); + return box->tag; +} + +int eve_text_putc(EVEText *box, int c) { + int line_c, line_n; + + switch (c) { + case '\b': + eve_text_backspace(box); + break; + case '\r': + case '\n': + eve_text_newline(box); + break; + default: + line_c = box->ch_idx / 2 / box->w; + + eve_write16(box->mem_addr + box->ch_idx, 0x0200 | (c & 0xff)); + box->ch_idx = (box->ch_idx + 2) % (box->line_size * box->w * 2); + eve_write16(box->mem_addr + box->ch_idx, TEXT_CRSR); + + line_n = box->ch_idx / 2 / box->w; + if ((line_c != line_n) && (LINE_IDX_DIFF(line_n, box->line0, box->line_size) == box->h)) scroll1(box); + break; + } + return EVE_OK; +} + +void eve_text_update(EVEText *box) { + int text_h1; + int text_h2; + int line_top; + + line_top = box->line_top >= 0 ? box->line_top : box->line0; + + if (line_top + box->h > box->line_size) { + text_h1 = box->line_size - line_top; + text_h2 = box->h - text_h1; + } else { + text_h1 = box->h; + text_h2 = 0; + } + eve_dl_start(box->mem_addr + box->w * 2 * box->line_size); + + eve_dl_write(SAVE_CONTEXT()); + eve_dl_write(BEGIN(EVE_BITMAPS)); + eve_dl_write(TAG(box->tag)); + eve_dl_write(VERTEX_FORMAT(0)); + eve_dl_write(BITMAP_HANDLE(15)); + if (box->transform_a != 256) { + eve_dl_write(BITMAP_TRANSFORM_A(box->transform_a)); + } + if (box->transform_e != 256) { + eve_dl_write(BITMAP_TRANSFORM_E(box->transform_e)); + } + eve_dl_write(BITMAP_SOURCE(box->mem_addr + line_top * box->w * 2)); + eve_dl_write(BITMAP_LAYOUT(EVE_TEXTVGA, box->w * 2, text_h1)); + eve_dl_write(BITMAP_SIZE(EVE_NEAREST, EVE_BORDER, EVE_BORDER, box->w * box->ch_w, text_h1 * box->ch_h)); + eve_dl_write(BITMAP_SIZE_H(box->w * box->ch_w, text_h1 * box->ch_h)); + eve_dl_write(VERTEX2F(box->g.x, box->g.y)); + + if (text_h2) { + eve_dl_write(BITMAP_SOURCE(box->mem_addr)); + eve_dl_write(BITMAP_LAYOUT(EVE_TEXTVGA, box->w * 2, text_h2)); + eve_dl_write(BITMAP_SIZE(EVE_NEAREST, EVE_BORDER, EVE_BORDER, box->w * box->ch_w, text_h2 * box->ch_h)); + eve_dl_write(BITMAP_SIZE_H(box->w * box->ch_w, text_h2 * box->ch_h)); + eve_dl_write(VERTEX2F(box->g.x, box->g.y + text_h1 * box->ch_h)); + } else { + eve_dl_write(NOP()); + eve_dl_write(NOP()); + eve_dl_write(NOP()); + eve_dl_write(NOP()); + eve_dl_write(NOP()); + } + + eve_dl_write(END()); + eve_dl_write(RESTORE_CONTEXT()); +} + +void eve_text_newline(EVEText *box) { + int line = (box->ch_idx / 2 / box->w + 1) % box->line_size; + + eve_write16(box->mem_addr + box->ch_idx, 0); + box->ch_idx = line * box->w * 2; + if (LINE_IDX_DIFF(line, box->line0, box->line_size) == box->h) scroll1(box); + eve_write16(box->mem_addr + box->ch_idx, TEXT_CRSR); +} + +void eve_text_backspace(EVEText *box) { + uint16_t c; + + eve_write16(box->mem_addr + box->ch_idx, 0); + box->ch_idx = (box->ch_idx - 2) % (box->line_size * box->w * 2); + if (eve_read16(box->mem_addr + box->ch_idx) == 0) { + box->ch_idx = (box->ch_idx + 2) % (box->line_size * box->w * 2); + } + eve_write16(box->mem_addr + box->ch_idx, TEXT_CRSR); +} diff --git a/fw/fe310/eos/eve/eve_text.h b/fw/fe310/eos/eve/eve_text.h new file mode 100644 index 0000000..141816c --- /dev/null +++ b/fw/fe310/eos/eve/eve_text.h @@ -0,0 +1,28 @@ +#include <stdint.h> + +typedef struct EVEText { + EVERect g; + uint16_t w; + uint16_t h; + uint32_t mem_addr; + uint16_t line_size; + uint16_t line0; + int line_top; + int line_top0; + uint16_t ch_idx; + uint16_t transform_a; + uint16_t transform_e; + uint8_t tag; + uint8_t ch_h; + uint8_t ch_w; + uint8_t dl_size; + char dirty; +} EVEText; + +void eve_text_init(EVEText *box, EVERect *g, uint16_t w, uint16_t h, uint8_t tag, uint16_t line_size, uint32_t mem_addr, uint32_t *mem_next); +int eve_text_touch(EVEText *box, uint8_t tag0, int touch_idx); +uint8_t eve_text_draw(EVEText *box); +int eve_text_putc(EVEText *box, int c); +void eve_text_update(EVEText *box); +void eve_text_newline(EVEText *box); +void eve_text_backspace(EVEText *box); diff --git a/fw/fe310/eos/eve/eve_touch.c b/fw/fe310/eos/eve/eve_touch.c new file mode 100644 index 0000000..a6db581 --- /dev/null +++ b/fw/fe310/eos/eve/eve_touch.c @@ -0,0 +1,396 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" + +#define EVE_THRESHOLD_X 5 +#define EVE_THRESHOLD_Y 5 +#define EVE_TIMEOUT_TAP 1000 +#define EVE_TIMEOUT_TRACK 20 +#define EVE_TRAVG 3 + +#define EVE_NOTOUCH 0x80000000 + +#define EVE_MAX_TOUCH 5 + +static int _intr_mask = EVE_INT_TAG | EVE_INT_TOUCH; +static int _multitouch; +static uint8_t _tag0; + +static EVETouch _touch[EVE_MAX_TOUCH]; +static EVETouchTimer _touch_timer; +static EVEExtTracker _ext_tracker; + +static eve_touch_handler_t _touch_handler; +static void *_touch_handler_param; +static uint8_t _tag_opt[256]; + +static const uint32_t _reg_touch[] = { + REG_CTOUCH_TOUCH0_XY, + REG_CTOUCH_TOUCH1_XY, + REG_CTOUCH_TOUCH2_XY, + REG_CTOUCH_TOUCH3_XY +}; + +static const uint32_t _reg_tag[] = { + REG_TOUCH_TAG, + REG_TOUCH_TAG1, + REG_TOUCH_TAG2, + REG_TOUCH_TAG3, + REG_TOUCH_TAG4 +}; + +static const uint32_t _reg_track[] = { + REG_TRACKER, + REG_TRACKER_1, + REG_TRACKER_2, + REG_TRACKER_3, + REG_TRACKER_4 +}; + +static void _touch_timer_set(uint8_t tag, uint8_t idx, uint16_t evt, int x0, int y0, uint32_t to) { + _touch_timer.tag = tag; + _touch_timer.idx = idx; + _touch_timer.evt = evt; + _touch_timer.x0 = x0; + _touch_timer.y0 = y0; + eve_timer_set(to); +} + +static void _touch_timer_clear(void) { + eve_timer_clear(); + _touch_timer.tag = 0; + _touch_timer.evt = 0; +} + +void eve_handle_touch(void) { + int i; + char touch_ex = 0; + char int_ccomplete = 0; + uint8_t tag0 = _tag0; + uint8_t touch_last = 0; + uint8_t flags = eve_read8(REG_INT_FLAGS) & _intr_mask; + + if (!_multitouch && (flags & EVE_INT_TOUCH)) _multitouch = 1; + for (i=0; i<EVE_MAX_TOUCH; i++) { + uint8_t touch_tag; + uint32_t touch_xy; + uint64_t now = 0; + EVETouch *touch = &_touch[i]; + + touch->evt = 0; + touch_xy = i < 4 ? eve_read32(_reg_touch[i]) : (((uint32_t)eve_read16(REG_CTOUCH_TOUCH4_X) << 16) | eve_read16(REG_CTOUCH_TOUCH4_Y)); + + if (touch_xy != 0x80008000) { + int16_t touch_x = touch_xy >> 16; + int16_t touch_y = touch_xy & 0xffff; + now = eve_time_get_tick(); + if (touch->x == EVE_NOTOUCH) { + uint16_t _evt = 0; + uint16_t _eevt = 0; + + if (!_tag0 && _touch_timer.tag) { + if (_touch_timer.evt & EVE_TOUCH_ETYPE_TAP1) { + int dx = touch_x - touch->x0; + int dy = touch_y - touch->y0; + dx = dx < 0 ? -dx : dx; + dy = dy < 0 ? -dy : dy; + if ((dx > EVE_THRESHOLD_X) || (dy > EVE_THRESHOLD_Y)) { + touch->evt |= EVE_TOUCH_ETYPE_TAP1; + } else { + _evt |= EVE_TOUCH_ETYPE_TAP2; + _eevt |= EVE_TOUCH_EETYPE_TAP2; + } + } + if (_touch_timer.evt & EVE_TOUCH_ETYPE_TRACK) { + touch->evt |= EVE_TOUCH_ETYPE_TRACK_STOP; + if (_ext_tracker.stop) _ext_tracker.stop(&_touch_timer, touch); + } + if (_touch_handler && touch->evt) { + _touch_handler(_touch_handler_param, _touch_timer.tag, i); + } + _touch_timer_clear(); + } + touch->evt = EVE_TOUCH_ETYPE_POINT | _eevt; + touch->eevt = _eevt; + touch->tag0 = 0; + touch->tag = 0; + touch->tag_up = 0; + touch->tracker.tag = 0; + touch->tracker.track = 0; + touch->tracker.val = 0; + touch->t = 0; + touch->vx = 0; + touch->vy = 0; + touch->x0 = touch_x; + touch->y0 = touch_y; + } else if (touch->t) { + int dt = now - touch->t; + int vx = ((int)touch_x - touch->x) * (int)(EVE_RTC_FREQ) / dt; + int vy = ((int)touch_y - touch->y) * (int)(EVE_RTC_FREQ) / dt; + touch->vx = touch->vx ? (vx + touch->vx * EVE_TRAVG) / (EVE_TRAVG + 1) : vx; + touch->vy = touch->vy ? (vy + touch->vy * EVE_TRAVG) / (EVE_TRAVG + 1) : vy; + touch->t = now; + } + touch->x = touch_x; + touch->y = touch_y; + if (_multitouch || (flags & EVE_INT_TAG)) { + touch_tag = eve_read8(_reg_tag[i]); + } else { + touch_tag = touch->tag; + } + touch_ex = 1; + } else { + touch_tag = 0; + if (touch->x != EVE_NOTOUCH) { + touch->evt |= EVE_TOUCH_ETYPE_POINT_UP; + if (_touch_timer.tag && (i == 0)) { + _touch_timer.evt &= ~EVE_TOUCH_ETYPE_LPRESS; + if (!_touch_timer.evt) _touch_timer_clear(); + } + if (touch->tracker.tag && touch->tracker.track) { + if (!_touch_timer.tag && (_tag_opt[touch->tracker.tag] & EVE_TOUCH_OPT_TRACK_EXT)) { + _touch_timer_set(touch->tracker.tag, i, EVE_TOUCH_ETYPE_TRACK, touch->x, touch->y, EVE_TIMEOUT_TRACK); + if (_ext_tracker.init) _ext_tracker.init(&_touch_timer, touch); + } else { + touch->evt |= EVE_TOUCH_ETYPE_TRACK_STOP; + } + } + touch->x = EVE_NOTOUCH; + touch->y = EVE_NOTOUCH; + } + } + if (touch_tag != touch->tag) { + if (touch_tag) { + if (!touch->tag0) { + touch->tag0 = touch_tag; + if (_tag_opt[touch_tag] & EVE_TOUCH_OPT_TRACK_MASK) { + touch->tracker.tag = touch_tag; + } + if (touch->tracker.tag && !(_tag_opt[touch->tracker.tag] & EVE_TOUCH_OPT_TRACK_XY)) { + touch->tracker.track = 1; + touch->evt |= EVE_TOUCH_ETYPE_TRACK_START; + touch->t = now; + } + if (!_tag0 && (_tag_opt[touch_tag] & EVE_TOUCH_OPT_TIMER_MASK)) { + uint16_t _evt = 0; + + if (_tag_opt[touch_tag] & EVE_TOUCH_OPT_LPRESS) _evt |= EVE_TOUCH_ETYPE_LPRESS; + if (_tag_opt[touch_tag] & EVE_TOUCH_OPT_DTAP) _evt |= EVE_TOUCH_ETYPE_TAP1; + _touch_timer_set(touch_tag, 0, _evt, 0, 0, EVE_TIMEOUT_TAP); + } + } + if (!_tag0) _tag0 = tag0 = touch_tag; + } + touch->tag_up = touch->tag; + if (touch->tag_up) touch->evt |= EVE_TOUCH_ETYPE_TAG_UP; + touch->tag = touch_tag; + if (touch->tag) touch->evt |= EVE_TOUCH_ETYPE_TAG; + } + if (touch_xy != 0x80008000) { + char _track = touch->tracker.tag && !touch->tracker.track; + char _timer = _touch_timer.tag && (_touch_timer.evt & EVE_TOUCH_ETYPE_TIMER_MASK) && (i == 0); + if (_track || _timer) { + int dx = touch->x - touch->x0; + int dy = touch->y - touch->y0; + dx = dx < 0 ? -dx : dx; + dy = dy < 0 ? -dy : dy; + if (_track) { + if ((dx > EVE_THRESHOLD_X) && !(_tag_opt[touch->tracker.tag] & EVE_TOUCH_OPT_TRACK_X)) { + touch->tracker.tag = 0; + } + if ((dy > EVE_THRESHOLD_Y) && !(_tag_opt[touch->tracker.tag] & EVE_TOUCH_OPT_TRACK_Y)) { + touch->tracker.tag = 0; + } + if (touch->tracker.tag && ((dx > EVE_THRESHOLD_X) || (dy > EVE_THRESHOLD_Y))) { + if (dx > EVE_THRESHOLD_X) { + touch->eevt |= touch->x > touch->x0 ? EVE_TOUCH_EETYPE_TRACK_RIGHT : EVE_TOUCH_EETYPE_TRACK_LEFT; + } + if (dy > EVE_THRESHOLD_Y) { + touch->eevt |= touch->y > touch->y0 ? EVE_TOUCH_EETYPE_TRACK_DOWN : EVE_TOUCH_EETYPE_TRACK_UP; + } + touch->tracker.track = 1; + touch->evt |= EVE_TOUCH_ETYPE_TRACK_START; + touch->t = now; + } + } + if (_timer && ((dx > EVE_THRESHOLD_X) || (dy > EVE_THRESHOLD_Y))) { + _touch_timer.evt &= ~EVE_TOUCH_ETYPE_TIMER_MASK; + if (!_touch_timer.evt) _touch_timer_clear(); + } + } + if (touch->tracker.tag && touch->tracker.track) { + touch->evt |= _tag_opt[touch->tracker.tag] & EVE_TOUCH_OPT_TRACK_MASK; + } + if (touch->evt & EVE_TOUCH_ETYPE_TRACK_REG) { + uint32_t touch_track = eve_read32(_reg_track[i]); + if (touch->tracker.tag == (touch_track & 0xff)) { + touch->tracker.val = touch_track >> 16; + } else { + touch->evt &= ~EVE_TOUCH_ETYPE_TRACK_REG; + } + } + if (touch->tracker.tag || _touch_timer.tag) int_ccomplete = 1; + } + if (touch->evt) touch_last = i + 1; + if (!_multitouch) break; + } + + if (!touch_ex) { + _tag0 = 0; + _multitouch = 0; + } + + if (_multitouch) int_ccomplete = 1; + + if (int_ccomplete && !(_intr_mask & EVE_INT_CONVCOMPLETE)) { + _intr_mask |= EVE_INT_CONVCOMPLETE; + eve_write8(REG_INT_MASK, _intr_mask); + } + if (!int_ccomplete && (_intr_mask & EVE_INT_CONVCOMPLETE)) { + _intr_mask &= ~EVE_INT_CONVCOMPLETE; + eve_write8(REG_INT_MASK, _intr_mask); + } + + for (i=0; i<touch_last; i++) { + EVETouch *touch = &_touch[i]; + if (_touch_handler && touch->evt) { + _touch_handler(_touch_handler_param, tag0, i); + } + } +} + +void eve_handle_time(void) { + if (_touch_handler && _touch_timer.tag) { + EVETouch *touch = &_touch[_touch_timer.idx]; + + if ((_touch_timer.evt & EVE_TOUCH_ETYPE_TAP1) && (touch->x != EVE_NOTOUCH)) _touch_timer.evt &= ~EVE_TOUCH_ETYPE_TAP1; + + if (_touch_timer.evt) { + int more = 0; + int _x = touch->x; + int _y = touch->y; + + touch->evt = _touch_timer.evt; + if (touch->evt & EVE_TOUCH_ETYPE_TRACK) { + if (_ext_tracker.tick) more = _ext_tracker.tick(&_touch_timer, touch); + if (more) { + eve_timer_set(EVE_TIMEOUT_TRACK); + } else { + touch->evt |= EVE_TOUCH_ETYPE_TRACK_STOP; + if (_ext_tracker.stop) _ext_tracker.stop(&_touch_timer, touch); + } + } else if (touch->evt & EVE_TOUCH_ETYPE_LPRESS) { + touch->eevt |= EVE_TOUCH_EETYPE_LPRESS; + } + + _touch_handler(_touch_handler_param, _touch_timer.tag, _touch_timer.idx); + + if (!more) _touch_timer_clear(); + touch->x = _x; + touch->y = _y; + } else { + _touch_timer_clear(); + } + } +} + +void eve_touch_init(void) { + int i; + + for (i=0; i<EVE_MAX_TOUCH; i++) { + EVETouch *touch = &_touch[i]; + touch->x = EVE_NOTOUCH; + touch->y = EVE_NOTOUCH; + } + eve_write8(REG_INT_MASK, _intr_mask); + eve_write8(REG_INT_EN, 0x01); + while(eve_read8(REG_INT_FLAGS)); +} + +void eve_touch_set_handler(eve_touch_handler_t handler, void *param) { + _touch_handler = handler; + _touch_handler_param = param; +} + +EVETouch *eve_touch_evt(uint8_t tag0, int touch_idx, uint8_t tag_min, uint8_t tag_n, uint16_t *evt) { + int tag_max; + uint8_t _tag; + uint16_t _evt; + EVETouch *ret = NULL; + + *evt = 0; + + if ((touch_idx < 0) || (touch_idx > 4)) return ret; + if (tag_min == EVE_TAG_NOTAG) return ret; + + tag_max = tag_min + tag_n; + if ((tag0 < tag_min) || (tag0 >= tag_max)) return ret; + + ret = &_touch[touch_idx]; + _evt = ret->evt; + + *evt |= _evt & EVE_TOUCH_ETYPE_POINT_MASK; + if (_evt & EVE_TOUCH_ETYPE_TAG) { + _tag = ret->tag; + if ((_tag >= tag_min) && (_tag < tag_max)) *evt |= EVE_TOUCH_ETYPE_TAG; + } + if (_evt & EVE_TOUCH_ETYPE_TAG_UP) { + _tag = ret->tag_up; + if ((_tag >= tag_min) && (_tag < tag_max)) *evt |= EVE_TOUCH_ETYPE_TAG_UP; + } + if (_evt & EVE_TOUCH_ETYPE_TRACK_REG) { + _tag = ret->tracker.tag; + if ((_tag >= tag_min) && (_tag < tag_max)) *evt |= EVE_TOUCH_ETYPE_TRACK_REG; + } + if (_evt & EVE_TOUCH_ETYPE_TRACK_MASK) { + _tag = ret->tracker.tag; + if ((_tag >= tag_min) && (_tag < tag_max)) *evt |= _evt & EVE_TOUCH_ETYPE_TRACK_MASK; + } + if (_evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TAP1 | EVE_TOUCH_ETYPE_TAP2)) { + _tag = _touch_timer.tag; + if ((_tag >= tag_min) && (_tag < tag_max)) *evt |= _evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TAP1 | EVE_TOUCH_ETYPE_TAP2); + } + + return ret; +} + +void eve_touch_set_opt(uint8_t tag, uint8_t opt) { + _tag_opt[tag] = opt; +} + +uint8_t eve_touch_get_opt(uint8_t tag) { + return _tag_opt[tag]; +} + +void eve_touch_clear_opt(void) { + memset(_tag_opt, 0, sizeof(_tag_opt)); +} + +EVETouchTimer *eve_touch_get_timer(void) { + return &_touch_timer; +} + +void eve_etrack_set(eve_etrack_init_t init, eve_etrack_tick_t tick, eve_etrack_stop_t stop, void *param) { + _ext_tracker.init = init; + _ext_tracker.tick = tick; + _ext_tracker.stop = stop; + _touch_timer.p = param; +} + +void eve_etrack_start(int i) { + EVETouch *touch = &_touch[i]; + + _touch_timer_set(touch->tracker.tag, i, EVE_TOUCH_ETYPE_TRACK, touch->x, touch->y, EVE_TIMEOUT_TRACK); + if (_ext_tracker.init) _ext_tracker.init(&_touch_timer, touch); +} + +void eve_etrack_stop(void) { + if (_ext_tracker.stop) { + EVETouch *touch = &_touch[_touch_timer.idx]; + + touch->evt = EVE_TOUCH_ETYPE_TRACK_STOP; + _ext_tracker.stop(&_touch_timer, touch); + } + _touch_timer_clear(); +} diff --git a/fw/fe310/eos/eve/eve_touch.h b/fw/fe310/eos/eve/eve_touch.h new file mode 100644 index 0000000..9f935bc --- /dev/null +++ b/fw/fe310/eos/eve/eve_touch.h @@ -0,0 +1,102 @@ +#include <stdint.h> + +/* events */ +#define EVE_TOUCH_ETYPE_TRACK 0x0001 +#define EVE_TOUCH_ETYPE_TRACK_REG 0x0002 +#define EVE_TOUCH_ETYPE_TRACK_START 0x0004 +#define EVE_TOUCH_ETYPE_TRACK_STOP 0x0008 +#define EVE_TOUCH_ETYPE_TAG 0x0010 +#define EVE_TOUCH_ETYPE_TAG_UP 0x0020 +#define EVE_TOUCH_ETYPE_POINT 0x0040 +#define EVE_TOUCH_ETYPE_POINT_UP 0x0080 +#define EVE_TOUCH_ETYPE_LPRESS 0x0100 +#define EVE_TOUCH_ETYPE_TAP1 0x0200 +#define EVE_TOUCH_ETYPE_TAP2 0x0400 + +#define EVE_TOUCH_ETYPE_TAG_MASK (EVE_TOUCH_ETYPE_TAG | EVE_TOUCH_ETYPE_TAG_UP) +#define EVE_TOUCH_ETYPE_TAP_MASK (EVE_TOUCH_ETYPE_TAP1 | EVE_TOUCH_ETYPE_TAP2) +#define EVE_TOUCH_ETYPE_TRACK_MASK (EVE_TOUCH_ETYPE_TRACK | EVE_TOUCH_ETYPE_TRACK_START | EVE_TOUCH_ETYPE_TRACK_STOP) +#define EVE_TOUCH_ETYPE_POINT_MASK (EVE_TOUCH_ETYPE_POINT | EVE_TOUCH_ETYPE_POINT_UP) +#define EVE_TOUCH_ETYPE_TIMER_MASK (EVE_TOUCH_OPT_LPRESS | EVE_TOUCH_OPT_DTAP) + +/* extended events */ +#define EVE_TOUCH_EETYPE_LPRESS 0x0001 +#define EVE_TOUCH_EETYPE_TAP2 0x0002 + +#define EVE_TOUCH_EETYPE_TRACK_LEFT 0x1000 +#define EVE_TOUCH_EETYPE_TRACK_RIGHT 0x2000 +#define EVE_TOUCH_EETYPE_TRACK_UP 0x4000 +#define EVE_TOUCH_EETYPE_TRACK_DOWN 0x8000 + +#define EVE_TOUCH_EETYPE_TRACK_X (EVE_TOUCH_EETYPE_TRACK_LEFT | EVE_TOUCH_EETYPE_TRACK_RIGHT) +#define EVE_TOUCH_EETYPE_TRACK_Y (EVE_TOUCH_EETYPE_TRACK_UP | EVE_TOUCH_EETYPE_TRACK_DOWN) +#define EVE_TOUCH_EETYPE_TRACK_XY (EVE_TOUCH_EETYPE_TRACK_X | EVE_TOUCH_EETYPE_TRACK_Y) + +/* tag options */ +#define EVE_TOUCH_OPT_TRACK EVE_TOUCH_ETYPE_TRACK +#define EVE_TOUCH_OPT_TRACK_REG EVE_TOUCH_ETYPE_TRACK_REG +#define EVE_TOUCH_OPT_TRACK_X 0x04 +#define EVE_TOUCH_OPT_TRACK_Y 0x08 +#define EVE_TOUCH_OPT_TRACK_EXT 0x10 +#define EVE_TOUCH_OPT_LPRESS 0x40 +#define EVE_TOUCH_OPT_DTAP 0x80 + +#define EVE_TOUCH_OPT_TRACK_XY (EVE_TOUCH_OPT_TRACK_X | EVE_TOUCH_OPT_TRACK_Y) +#define EVE_TOUCH_OPT_TRACK_MASK (EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_REG) +#define EVE_TOUCH_OPT_TIMER_MASK (EVE_TOUCH_OPT_LPRESS | EVE_TOUCH_OPT_DTAP) + +typedef void (*eve_touch_handler_t) (void *, uint8_t, int); + +typedef struct EVETouch { + int x; + int y; + int vx; + int vy; + int x0; + int y0; + uint64_t t; + uint16_t evt; + uint16_t eevt; + uint8_t tag0; + uint8_t tag; + uint8_t tag_up; + struct { + uint8_t tag; + uint8_t track; + uint16_t val; + } tracker; +} EVETouch; + +typedef struct EVETouchTimer { + uint8_t tag; + uint8_t idx; + uint16_t evt; + int x0; + int y0; + void *p; +} EVETouchTimer; + +void eve_handle_touch(void); +void eve_handle_time(void); + +void eve_touch_init(void); +void eve_touch_set_handler(eve_touch_handler_t handler, void *handler_param); +EVETouch *eve_touch_evt(uint8_t tag0, int touch_idx, uint8_t tag_min, uint8_t tag_n, uint16_t *evt); +void eve_touch_set_opt(uint8_t tag, uint8_t opt); +uint8_t eve_touch_get_opt(uint8_t tag); +void eve_touch_clear_opt(void); +EVETouchTimer *eve_touch_get_timer(void); + +typedef void (*eve_etrack_init_t) (EVETouchTimer *, EVETouch *); +typedef int (*eve_etrack_tick_t) (EVETouchTimer *, EVETouch *); +typedef void (*eve_etrack_stop_t) (EVETouchTimer *, EVETouch *); + +typedef struct EVEExtTracker { + eve_etrack_init_t init; + eve_etrack_tick_t tick; + eve_etrack_stop_t stop; +} EVEExtTracker; + +void eve_etrack_set(eve_etrack_init_t init, eve_etrack_tick_t tick, eve_etrack_stop_t stop, void *param); +void eve_etrack_start(int i); +void eve_etrack_stop(void); diff --git a/fw/fe310/eos/eve/eve_track.c b/fw/fe310/eos/eve/eve_track.c new file mode 100644 index 0000000..97ef72b --- /dev/null +++ b/fw/fe310/eos/eve/eve_track.c @@ -0,0 +1,77 @@ +#include <stdlib.h> +#include <math.h> + +#include "eve.h" + +void eve_track_init(void) { + eve_etrack_set(eve_track_inert_init, eve_track_inert_tick, NULL, NULL); +} + +void eve_track_set(uint8_t type, void *param) { + switch (type) { + case EVE_TRACK_TYPE_INERT: + eve_etrack_set(eve_track_inert_init, eve_track_inert_tick, NULL, NULL); + break; + case EVE_TRACK_TYPE_OSC: + eve_etrack_set(NULL, eve_track_osc_tick, NULL, param); + break; + default: + break; + } +} + +void eve_track_inert_init(EVETouchTimer *timer, EVETouch *touch) { + double d = sqrt(touch->vx * touch->vx + touch->vy * touch->vy); + int fc = (double)(EVE_RTC_FREQ) * d / EVE_TRACK_FRICTION; + + timer->p = (void *)fc; +} + +int eve_track_inert_tick(EVETouchTimer *timer, EVETouch *touch) { + int dt = eve_time_get_tick() - touch->t; + int fc = (int)timer->p; + int more = 1; + + if (dt >= fc / 2) { + dt = fc / 2; + more = 0; + } + touch->x = timer->x0 + (touch->vx * dt - touch->vx * dt / fc * dt) / (int)(EVE_RTC_FREQ); + touch->y = timer->y0 + (touch->vy * dt - touch->vy * dt / fc * dt) / (int)(EVE_RTC_FREQ); + return more; +} + +void eve_track_osc_init(EVETrackOsc *p, int x, int y, uint32_t T, double d, uint32_t t_max) { + double f0 = 2 * M_PI / (T * EVE_RTC_FREQ / 1000); + + if (d < 0) d = 0; + if (d > 1) d = 1; + p->x = x; + p->y = y; + p->f = d ? f0 * sqrt(1 - d * d) : f0; + p->d = d; + p->a = -d * f0; + p->t_max = t_max; +} + +int eve_track_osc_tick(EVETouchTimer *timer, EVETouch *touch) { + EVETrackOsc *p = (EVETrackOsc *)timer->p; + int dt = eve_time_get_tick() - touch->t; + int ax = timer->x0 - p->x; + int ay = timer->y0 - p->y; + int more = 1; + + if (p->t_max && (dt >= p->t_max)) { + dt = p->t_max; + more = 0; + } + if (p->d) { + double e = exp(p->a * dt); + ax = ax * e; + ay = ay * e; + if ((ax == 0) && (ay == 0)) more = 0; + } + touch->x = p->x + ax * cos(p->f * dt); + touch->y = p->y + ay * cos(p->f * dt); + return more; +} diff --git a/fw/fe310/eos/eve/eve_track.h b/fw/fe310/eos/eve/eve_track.h new file mode 100644 index 0000000..a5fd113 --- /dev/null +++ b/fw/fe310/eos/eve/eve_track.h @@ -0,0 +1,22 @@ +#include <stdint.h> + +#define EVE_TRACK_TYPE_INERT 1 +#define EVE_TRACK_TYPE_OSC 2 +#define EVE_TRACK_FRICTION 500 + +typedef struct EVETrackOsc { + int x; + int y; + double f; + double d; + double a; + uint32_t t_max; +} EVETrackOsc; + +void eve_track_init(void); +void eve_track_set(uint8_t type, void *param); + +void eve_track_inert_init(EVETouchTimer *timer, EVETouch *touch); +int eve_track_inert_tick(EVETouchTimer *timer, EVETouch *touch); +void eve_track_osc_init(EVETrackOsc *p, int x, int y, uint32_t T, double d, uint32_t t_max); +int eve_track_osc_tick(EVETouchTimer *timer, EVETouch *touch); diff --git a/fw/fe310/eos/eve/screen/Makefile b/fw/fe310/eos/eve/screen/Makefile new file mode 100644 index 0000000..b6cb393 --- /dev/null +++ b/fw/fe310/eos/eve/screen/Makefile @@ -0,0 +1,17 @@ +include ../../../common.mk + +CFLAGS += -I.. -I../.. + +obj = font.o screen.o window.o kbdwin.o page.o form.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o
\ No newline at end of file diff --git a/fw/fe310/eos/eve/screen/font.c b/fw/fe310/eos/eve/screen/font.c new file mode 100644 index 0000000..da02983 --- /dev/null +++ b/fw/fe310/eos/eve/screen/font.c @@ -0,0 +1,61 @@ +#include <stdlib.h> + +#include "eve.h" +#include "unicode.h" + +#include "font.h" + +void eve_font_init(EVEFont *font, uint8_t font_id) { + uint32_t p; + + p = eve_read32(EVE_ROM_FONT_ADDR); + p += (148 * (font_id - 16)); + font->id = font_id; + font->w = eve_read32(p + 136); + font->h = eve_read32(p + 140); + eve_readb(p, font->w_ch, 128); +} + +uint8_t eve_font_ch_w(EVEFont *font, utf32_t ch) { + if (ch < 128) return font->w_ch[ch]; + return 0; +} + +uint16_t eve_font_str_w(EVEFont *font, utf8_t *str) { + uint16_t r = 0; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + + if (str == NULL) return 0; + + while (*str) { + ch_l = utf8_dec(str, &ch); + ch_w = eve_font_ch_w(font, ch); + r += ch_w; + str += ch_l; + } + + return r; +} + +uint16_t eve_font_buf_w(EVEFont *font, utf8_t *buf, uint16_t buf_len) { + int i = 0; + uint16_t r = 0; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + + while (i < buf_len) { + ch_l = utf8_dec(buf + i, &ch); + ch_w = eve_font_ch_w(font, ch); + r += ch_w; + i += ch_l; + } + + return r; +} + +uint8_t eve_font_h(EVEFont *font) { + return font->h; +}
\ No newline at end of file diff --git a/fw/fe310/eos/eve/screen/font.h b/fw/fe310/eos/eve/screen/font.h new file mode 100644 index 0000000..aff038c --- /dev/null +++ b/fw/fe310/eos/eve/screen/font.h @@ -0,0 +1,14 @@ +#include <stdint.h> + +typedef struct EVEFont { + uint8_t id; + uint8_t w; + uint8_t h; + uint8_t w_ch[128]; +} EVEFont; + +void eve_font_init(EVEFont *font, uint8_t font_id); +uint8_t eve_font_ch_w(EVEFont *font, utf32_t ch); +uint16_t eve_font_str_w(EVEFont *font, utf8_t *str); +uint16_t eve_font_buf_w(EVEFont *font, utf8_t *buf, uint16_t buf_len); +uint8_t eve_font_h(EVEFont *font); diff --git a/fw/fe310/eos/eve/screen/form.c b/fw/fe310/eos/eve/screen/form.c new file mode 100644 index 0000000..f7d37ee --- /dev/null +++ b/fw/fe310/eos/eve/screen/form.c @@ -0,0 +1,109 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen.h" +#include "window.h" +#include "page.h" +#include "font.h" +#include "form.h" + +#include "widget/label.h" +#include "widget/widget.h" + +int eve_form_init(EVEForm *form, EVEWindow *window, EVEWidget *widget, uint16_t widget_size, eve_page_open_t open, eve_page_close_t close) { + memset(form, 0, sizeof(EVEForm)); + eve_page_init(&form->p, window, eve_form_touch, eve_form_draw, open, close, eve_form_handle_evt, eve_form_update_g); + form->widget = widget; + form->widget_size = widget_size; + eve_form_update_g(&form->p, NULL); +} + +int eve_form_touch(EVEView *v, uint8_t tag0, int touch_idx) { + EVEForm *form = (EVEForm *)v; + EVEWidget *widget = form->widget; + int i, ret = 0; + + if (touch_idx == 0) { + EVETouch *t; + uint16_t evt; + + t = eve_touch_evt(tag0, touch_idx, form->p.v.window->tag, 1, &evt); + if (t && evt) { + eve_form_handle_evt(&form->p, NULL, t, evt, tag0, touch_idx); + if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && (t->eevt == 0)) eve_page_set_focus(&form->p, NULL, NULL); + ret = 1; + } + } + for (i=0; i<form->widget_size; i++) { + if (eve_page_rect_visible(&form->p, &widget->g)) { + int r = widget->touch(widget, &form->p, tag0, touch_idx); + ret = ret || r; + } + widget = eve_widget_next(widget); + } + + return ret; +} + +uint8_t eve_form_draw(EVEView *v, uint8_t tag0) { + EVEForm *form = (EVEForm *)v; + EVEWidget *widget = form->widget; + int i; + uint8_t tagN = tag0; + + eve_cmd_dl(SAVE_CONTEXT()); + eve_cmd_dl(VERTEX_FORMAT(0)); + eve_cmd_dl(VERTEX_TRANSLATE_X(eve_page_scr_x(&form->p, 0) * 16)); + eve_cmd_dl(VERTEX_TRANSLATE_Y(eve_page_scr_y(&form->p, 0) * 16)); + + for (i=0; i<form->widget_size; i++) { + if (widget->label && eve_page_rect_visible(&form->p, &widget->label->g)) { + eve_cmd_dl(TAG_MASK(0)); + eve_label_draw(widget->label); + eve_cmd_dl(TAG_MASK(1)); + } + if (eve_page_rect_visible(&form->p, &widget->g)) tagN = widget->draw(widget, &form->p, tagN); + widget = eve_widget_next(widget); + } + + eve_cmd_dl(RESTORE_CONTEXT()); + + for (i=tag0; i<tagN; i++) { + eve_touch_set_opt(i, eve_touch_get_opt(i) | EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_XY | EVE_TOUCH_OPT_TRACK_EXT); + } + if (v->window->tag != EVE_TAG_NOTAG) eve_touch_set_opt(v->window->tag, eve_touch_get_opt(v->window->tag) | EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_XY | EVE_TOUCH_OPT_TRACK_EXT); + + return tagN; +} + +void eve_form_handle_evt(EVEPage *page, EVEWidget *widget, EVETouch *touch, uint16_t evt, uint8_t tag0, int touch_idx) { + /* + if (evt & EVE_TOUCH_ETYPE_TRACK_Y) { + // do scroll + } else { + // go back / forward + } + */ +} + +void eve_form_update_g(EVEPage *page, EVEWidget *_widget) { + EVEForm *form = (EVEForm *)page; + EVEWidget *widget = form->widget; + int i; + uint16_t h = 0; + + for (i=0; i<form->widget_size; i++) { + if (widget->label) { + widget->label->g.y = h; + if (widget->label->g.w + widget->g.w > form->p.v.window->g.w) h += widget->label->g.h; + } + widget->g.y = h; + h += widget->g.h; + + widget = eve_widget_next(widget); + } +} diff --git a/fw/fe310/eos/eve/screen/form.h b/fw/fe310/eos/eve/screen/form.h new file mode 100644 index 0000000..7742b8c --- /dev/null +++ b/fw/fe310/eos/eve/screen/form.h @@ -0,0 +1,15 @@ +#include <stdint.h> + +struct EVEWidget; + +typedef struct EVEForm { + EVEPage p; + struct EVEWidget *widget; + uint16_t widget_size; +} EVEForm; + +int eve_form_init(EVEForm *form, EVEWindow *window, struct EVEWidget *widget, uint16_t widget_size, eve_page_open_t open, eve_page_close_t close); +int eve_form_touch(EVEView *v, uint8_t tag0, int touch_idx); +uint8_t eve_form_draw(EVEView *v, uint8_t tag0); +void eve_form_handle_evt(EVEPage *page, struct EVEWidget *widget, EVETouch *touch, uint16_t evt, uint8_t tag0, int touch_idx); +void eve_form_update_g(EVEPage *page, struct EVEWidget *widget); diff --git a/fw/fe310/eos/eve/screen/kbdwin.c b/fw/fe310/eos/eve/screen/kbdwin.c new file mode 100644 index 0000000..decedad --- /dev/null +++ b/fw/fe310/eos/eve/screen/kbdwin.c @@ -0,0 +1,39 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" + +#include "screen.h" +#include "window.h" +#include "kbdwin.h" + +static int kbdwin_touch(EVEView *v, uint8_t tag0, int touch_idx) { + EVEKbdView *k_view = (EVEKbdView *)v; + + return eve_kbd_touch(&k_view->kbd, tag0, touch_idx); +} + +static uint8_t kbdwin_draw(EVEView *v, uint8_t tag0) { + EVEKbdView *k_view = (EVEKbdView *)v; + + eve_kbd_draw(&k_view->kbd); + return tag0; +} + +void eve_kbdwin_init(EVEKbdWin *kbd_win, EVEScreen *screen) { + EVEKbd *kbd = &kbd_win->view.kbd; + + kbd_win->view.v.touch = kbdwin_touch; + kbd_win->view.v.draw = kbdwin_draw; + eve_kbd_init(kbd, NULL, screen->mem_next, &screen->mem_next); + eve_window_init(&kbd_win->win, &kbd->g, &kbd_win->view.v, screen); +} + +void eve_kbdwin_append(EVEKbdWin *kbd_win) { + EVEKbd *kbd = &kbd_win->view.kbd; + EVEWindow *window = &kbd_win->win; + + eve_screen_set_kbd(window->screen, kbd); + eve_window_append(window); +} diff --git a/fw/fe310/eos/eve/screen/kbdwin.h b/fw/fe310/eos/eve/screen/kbdwin.h new file mode 100644 index 0000000..2cc14d9 --- /dev/null +++ b/fw/fe310/eos/eve/screen/kbdwin.h @@ -0,0 +1,14 @@ +#include <stdint.h> + +typedef struct EVEKbdView { + EVEView v; + EVEKbd kbd; +} EVEKbdView; + +typedef struct EVEKbdWin { + EVEWindow win; + EVEKbdView view; +} EVEKbdWin; + +void eve_kbdwin_init(EVEKbdWin *kbd_win, EVEScreen *screen); +void eve_kbdwin_append(EVEKbdWin *kbd_win); diff --git a/fw/fe310/eos/eve/screen/page.c b/fw/fe310/eos/eve/screen/page.c new file mode 100644 index 0000000..f54056c --- /dev/null +++ b/fw/fe310/eos/eve/screen/page.c @@ -0,0 +1,100 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen.h" +#include "window.h" +#include "page.h" +#include "font.h" + +#include "widget/label.h" +#include "widget/widget.h" + +#define CH_EOF 0x1a + +void eve_page_init(EVEPage *page, EVEWindow *window, eve_view_touch_t touch, eve_view_draw_t draw, eve_page_open_t open, eve_page_close_t close, eve_page_evt_handler_t handle_evt, eve_page_g_updater_t update_g) { + memset(page, 0, sizeof(EVEPage)); + page->v.touch = touch; + page->v.draw = draw; + page->v.window = window; + page->open = open; + page->close = close; + page->handle_evt = handle_evt; + page->update_g = update_g; + page->widget_f = NULL; + window->view = (EVEView *)page; +} + +int16_t eve_page_x(EVEPage *page, int16_t x) { + return x + page->win_x - page->v.window->g.x; +} + +int16_t eve_page_y(EVEPage *page, int16_t y) { + return y + page->win_y - page->v.window->g.y; +} + +int16_t eve_page_scr_x(EVEPage *page, int16_t x) { + return x - page->win_x + page->v.window->g.x; +} + +int16_t eve_page_scr_y(EVEPage *page, int16_t y) { + return y - page->win_y + page->v.window->g.y; +} + +void eve_page_set_focus(EVEPage *page, EVEWidget *widget, EVERect *f) { + if (page->widget_f != widget) { + EVEKbd *kbd = eve_screen_get_kbd(page->v.window->screen); + + if (kbd) { + EVEWidget *widget_f = page->widget_f; + + if (widget_f && widget_f->putc) { + eve_screen_hide_kbd(page->v.window->screen); + widget_f->putc(page, CH_EOF); + } + if (widget && widget->putc) { + eve_kbd_set_handler(kbd, widget->putc, page); + eve_screen_show_kbd(page->v.window->screen); + } else { + eve_kbd_set_handler(kbd, NULL, NULL); + } + } + page->widget_f = widget; + } + + if (f) { + EVERect g; + + eve_window_visible_g(page->v.window, &g); + g.x -= page->v.window->g.x; + g.y -= page->v.window->g.y; + + if (f->x < page->win_x + g.x) { + page->win_x = f->x - g.x; + } + if (f->y < page->win_y + g.y) { + page->win_y = f->y - g.y; + } + if ((f->x + f->w) > (page->win_x + g.x + g.w)) { + page->win_x = (f->x + f->w) - (g.x + g.w); + } + if ((f->y + f->h) > (page->win_y + g.y + g.h)) { + page->win_y = (f->y + f->h) - (g.y + g.h); + } + } +} + +EVEWidget *eve_page_get_focus(EVEPage *page) { + return page->widget_f; +} + +int eve_page_rect_visible(EVEPage *page, EVERect *g) { + uint16_t w = page->v.window->g.w; + uint16_t h = page->v.window->g.h; + + if (((g->x + g->w) >= page->win_x) && ((g->y + g->h) >= page->win_y) && (g->x <= (page->win_x + w)) && (g->y <= (page->win_y + h))) return 1; + return 0; +} diff --git a/fw/fe310/eos/eve/screen/page.h b/fw/fe310/eos/eve/screen/page.h new file mode 100644 index 0000000..eebedfd --- /dev/null +++ b/fw/fe310/eos/eve/screen/page.h @@ -0,0 +1,30 @@ +#include <stdint.h> + +struct EVEPage; +struct EVEWidget; + +typedef void (*eve_page_open_t) (struct EVEPage *, struct EVEPage *); +typedef void (*eve_page_close_t) (struct EVEPage *); +typedef void (*eve_page_evt_handler_t) (struct EVEPage *, struct EVEWidget *, EVETouch *, uint16_t, uint8_t, int); +typedef void (*eve_page_g_updater_t) (struct EVEPage *, struct EVEWidget *); + +typedef struct EVEPage { + EVEView v; + int16_t win_x; + int16_t win_y; + eve_page_open_t open; + eve_page_close_t close; + eve_page_evt_handler_t handle_evt; + eve_page_g_updater_t update_g; + struct EVEWidget *widget_f; +} EVEPage; + +void eve_page_init(EVEPage *page, EVEWindow *window, eve_view_touch_t touch, eve_view_draw_t draw, eve_page_open_t open, eve_page_close_t close, eve_page_evt_handler_t handle_evt, eve_page_g_updater_t update_g); +int16_t eve_page_x(EVEPage *page, int16_t x); +int16_t eve_page_y(EVEPage *page, int16_t y); +int16_t eve_page_scr_x(EVEPage *page, int16_t x); +int16_t eve_page_scr_y(EVEPage *page, int16_t y); + +void eve_page_set_focus(EVEPage *page, struct EVEWidget *widget, EVERect *focus); +struct EVEWidget *eve_page_get_focus(EVEPage *page); +int eve_page_rect_visible(EVEPage *page, EVERect *g); diff --git a/fw/fe310/eos/eve/screen/screen.c b/fw/fe310/eos/eve/screen/screen.c new file mode 100644 index 0000000..f103b48 --- /dev/null +++ b/fw/fe310/eos/eve/screen/screen.c @@ -0,0 +1,104 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" + +#include "screen.h" +#include "window.h" +#include "kbdwin.h" + +int eve_screen_init(EVEScreen *screen, uint16_t w, uint16_t h) { + memset(screen, 0, sizeof(EVEScreen)); + screen->w = w; + screen->h = h; + screen->mem_next = EVE_RAM_G; + eve_touch_set_handler(eve_screen_handle_touch, screen); +} + +void eve_screen_set_kbd(EVEScreen *screen, EVEKbd *kbd) { + screen->kbd = kbd; +} + +EVEKbd *eve_screen_get_kbd(EVEScreen *screen) { + return screen->kbd; +} + +void eve_screen_show_kbd(EVEScreen *screen) { + EVEWindow *win = screen->win_tail; + EVEKbd *kbd = eve_screen_get_kbd(screen); + + if (win) win->g.y = screen->h - kbd->g.h; +} + +void eve_screen_hide_kbd(EVEScreen *screen) { + EVEWindow *win = screen->win_tail; + + if (win) win->g.y = screen->h; +} + +void eve_screen_draw(EVEScreen *screen) { + EVEWindow *win; + uint8_t tagN = 0x80; + + eve_cmd_burst_start(); + eve_cmd_dl(CMD_DLSTART); + + win = screen->win_head; + while (win) { + if (eve_window_visible(win)) { + int16_t x = win->g.x; + int16_t y = win->g.y; + uint16_t w = win->g.w; + uint16_t h = win->g.h; + + if (x < 0) { + w += x; + x = 0; + } + if (y < 0) { + h += y; + y = 0; + } + if (x + w > screen->w) w = screen->w - x; + if (y + h > screen->h) h = screen->h - y; + win->tag = tagN; + + if (tagN != EVE_TAG_NOTAG) { + eve_cmd_dl(CLEAR_TAG(tagN)); + tagN++; + } + eve_cmd_dl(CLEAR_COLOR_RGBC(win->color_bg)); + eve_cmd_dl(SCISSOR_XY(x, y)); + eve_cmd_dl(SCISSOR_SIZE(w, h)); + eve_cmd_dl(CLEAR(1,1,1)); + eve_cmd_dl(COLOR_RGBC(win->color_fg)); + tagN = win->view->draw(win->view, tagN); + } + win = win->next; + } + + eve_cmd_dl(DISPLAY()); + eve_cmd_dl(CMD_SWAP); + eve_cmd_burst_end(); + eve_cmd_exec(1); +} + +void eve_screen_handle_touch(void *s, uint8_t tag0, int touch_idx) { + EVEScreen *screen = s; + EVEWindow *win; + + eve_touch_clear_opt(); + + if (touch_idx >= 0) { + win = screen->win_tail; + while (win) { + if (eve_window_visible(win)) { + int a = win->view->touch(win->view, tag0, touch_idx); + } + win = win->prev; + } + } + + eve_screen_draw(screen); +} diff --git a/fw/fe310/eos/eve/screen/screen.h b/fw/fe310/eos/eve/screen/screen.h new file mode 100644 index 0000000..a9745ad --- /dev/null +++ b/fw/fe310/eos/eve/screen/screen.h @@ -0,0 +1,21 @@ +#include <stdint.h> + +struct EVEWindow; + +typedef struct EVEScreen { + uint16_t w; + uint16_t h; + uint32_t mem_next; + struct EVEWindow *win_head; + struct EVEWindow *win_tail; + EVEKbd *kbd; +} EVEScreen; + +int eve_screen_init(EVEScreen *screen, uint16_t w, uint16_t h); +void eve_screen_set_kbd(EVEScreen *screen, EVEKbd *kbd); +EVEKbd *eve_screen_get_kbd(EVEScreen *screen); +void eve_screen_show_kbd(EVEScreen *screen); +void eve_screen_hide_kbd(EVEScreen *screen); + +void eve_screen_draw(EVEScreen *screen); +void eve_screen_handle_touch(void *s, uint8_t tag0, int touch_idx); diff --git a/fw/fe310/eos/eve/screen/window.c b/fw/fe310/eos/eve/screen/window.c new file mode 100644 index 0000000..e49897f --- /dev/null +++ b/fw/fe310/eos/eve/screen/window.c @@ -0,0 +1,116 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" + +#include "screen.h" +#include "window.h" + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +void eve_window_init(EVEWindow *window, EVERect *g, EVEView *view, EVEScreen *screen) { + memset(window, 0, sizeof(EVEWindow)); + + if (g) window->g = *g; + if (view) { + window->view = view; + window->view->window = window; + } + window->screen = screen; + window->color_fg = 0xffffff; +} + +void eve_window_set_color_bg(EVEWindow *window, uint8_t r, uint8_t g, uint8_t b) { + window->color_bg = (r << 16) | (g << 8) | b; +} + +void eve_window_set_color_fg(EVEWindow *window, uint8_t r, uint8_t g, uint8_t b) { + window->color_fg = (r << 16) | (g << 8) | b; +} + +int eve_window_visible(EVEWindow *window) { + if (window->g.x >= window->screen->w) return 0; + if (window->g.y >= window->screen->h) return 0; + if ((window->g.x + window->g.w) <= 0) return 0; + if ((window->g.y + window->g.h) <= 0) return 0; + return 1; +} + +void eve_window_visible_g(EVEWindow *window, EVERect *g) { + EVEWindow *w = window->next; + + *g = window->g; + while (w) { + if (eve_window_visible(w)) { + if (w->g.x > g->x) g->w = MIN(g->w, w->g.x - g->x); + if (w->g.y > g->y) g->h = MIN(g->h, w->g.y - g->y); + if (w->g.x + w->g.w < g->x + g->w) { + uint16_t x0 = g->w - MIN(g->w, (g->x + g->w) - (w->g.x + w->g.w)); + g->x += x0; + g->w -= x0; + } + if (w->g.y + w->g.h < g->y + g->h) { + uint16_t y0 = g->h - MIN(g->h, (g->y + g->h) - (w->g.y + w->g.h)); + g->y += y0; + g->h -= y0; + } + } + w = w->next; + } +} + +void eve_window_append(EVEWindow *window) { + EVEScreen *screen = window->screen; + + window->prev = screen->win_tail; + if (screen->win_tail) { + screen->win_tail->next = window; + } else { + screen->win_head = window; + } + screen->win_tail = window; +} + +void eve_window_insert_above(EVEWindow *window, EVEWindow *win_prev) { + EVEScreen *screen = window->screen; + + window->prev = win_prev; + window->next = win_prev->next; + + if (window->next) { + window->next->prev = window; + } else { + screen->win_tail = window; + } + win_prev->next = window; +} + +void eve_window_insert_below(EVEWindow *window, EVEWindow *win_next) { + EVEScreen *screen = window->screen; + + window->prev = win_next->prev; + window->next = win_next; + + win_next->prev = window; + if (window->prev) { + window->prev->next = window; + } else { + screen->win_head = window; + } +} + +void eve_window_remove(EVEWindow *window) { + EVEScreen *screen = window->screen; + + if (window->prev) { + window->prev->next = window->next; + } else { + screen->win_head = window->next; + } + if (window->next) { + window->next->prev = window->prev; + } else { + screen->win_tail = window->prev; + } +} diff --git a/fw/fe310/eos/eve/screen/window.h b/fw/fe310/eos/eve/screen/window.h new file mode 100644 index 0000000..7f14f18 --- /dev/null +++ b/fw/fe310/eos/eve/screen/window.h @@ -0,0 +1,36 @@ +#include <stdint.h> + +struct EVEView; +struct EVEWindow; + +typedef int (*eve_view_touch_t) (struct EVEView *, uint8_t, int); +typedef uint8_t (*eve_view_draw_t) (struct EVEView *, uint8_t); + +typedef struct EVEView { + eve_view_touch_t touch; + eve_view_draw_t draw; + struct EVEWindow *window; +} EVEView; + +typedef struct EVEWindow { + EVERect g; + EVEView *view; + EVEScreen *screen; + struct EVEWindow *next; + struct EVEWindow *prev; + uint32_t color_bg; + uint32_t color_fg; + uint8_t tag; +} EVEWindow; + +void eve_window_init(EVEWindow *window, EVERect *g, EVEView *view, EVEScreen *screen); +void eve_window_set_color_bg(EVEWindow *window, uint8_t r, uint8_t g, uint8_t b); +void eve_window_set_color_fg(EVEWindow *window, uint8_t r, uint8_t g, uint8_t b); + +int eve_window_visible(EVEWindow *window); +void eve_window_visible_g(EVEWindow *window, EVERect *g); + +void eve_window_append(EVEWindow *window); +void eve_window_insert_above(EVEWindow *window, EVEWindow *win_prev); +void eve_window_insert_below(EVEWindow *window, EVEWindow *win_next); +void eve_window_remove(EVEWindow *window); diff --git a/fw/fe310/eos/eve/widget/Makefile b/fw/fe310/eos/eve/widget/Makefile new file mode 100644 index 0000000..160db72 --- /dev/null +++ b/fw/fe310/eos/eve/widget/Makefile @@ -0,0 +1,17 @@ +include ../../../common.mk + +CFLAGS += -I.. -I../.. + +obj = clipb.o label.o widget.o pagew.o strw.o textw.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/clipb.c b/fw/fe310/eos/eve/widget/clipb.c new file mode 100644 index 0000000..04c9a46 --- /dev/null +++ b/fw/fe310/eos/eve/widget/clipb.c @@ -0,0 +1,19 @@ +#include <string.h> + +#include "eve.h" +#include "clipb.h" + +static uint8_t _clipb[EVE_CLIPB_SIZE_BUF]; + +int eve_clipb_push(uint8_t *str, uint16_t len) { + if (len >= EVE_CLIPB_SIZE_BUF) return EVE_ERR; + + memcpy(_clipb, str, len); + _clipb[len] = '\0'; + + return EVE_OK; +} + +uint8_t *eve_clipb_get(void) { + return _clipb; +}
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/clipb.h b/fw/fe310/eos/eve/widget/clipb.h new file mode 100644 index 0000000..2d6fae6 --- /dev/null +++ b/fw/fe310/eos/eve/widget/clipb.h @@ -0,0 +1,6 @@ +#include <stdint.h> + +#define EVE_CLIPB_SIZE_BUF 256 + +int eve_clipb_push(uint8_t *str, uint16_t len); +uint8_t *eve_clipb_get(void);
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/label.c b/fw/fe310/eos/eve/widget/label.c new file mode 100644 index 0000000..ebea823 --- /dev/null +++ b/fw/fe310/eos/eve/widget/label.c @@ -0,0 +1,26 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen/screen.h" +#include "screen/window.h" +#include "screen/page.h" +#include "screen/font.h" + +#include "label.h" + +void eve_label_init(EVELabel *label, EVERect *g, EVEFont *font, char *title) { + memset(label, 0, sizeof(EVELabel)); + if (g) label->g = *g; + label->title = title; + label->font = font; + if (label->g.w == 0) label->g.w = eve_font_str_w(font, label->title); + if (label->g.h == 0) label->g.h = eve_font_h(font); +} + +void eve_label_draw(EVELabel *label) { + eve_cmd(CMD_TEXT, "hhhhs", label->g.x, label->g.y, label->font->id, 0, label->title); +}
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/label.h b/fw/fe310/eos/eve/widget/label.h new file mode 100644 index 0000000..ec96844 --- /dev/null +++ b/fw/fe310/eos/eve/widget/label.h @@ -0,0 +1,10 @@ +#include <stdint.h> + +typedef struct EVELabel { + EVERect g; + char *title; + EVEFont *font; +} EVELabel; + +void eve_label_init(EVELabel *label, EVERect *g, EVEFont *font, char *title); +void eve_label_draw(EVELabel *label);
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/pagew.c b/fw/fe310/eos/eve/widget/pagew.c new file mode 100644 index 0000000..c64c477 --- /dev/null +++ b/fw/fe310/eos/eve/widget/pagew.c @@ -0,0 +1,60 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen/screen.h" +#include "screen/window.h" +#include "screen/page.h" +#include "screen/font.h" + +#include "label.h" +#include "widget.h" +#include "pagew.h" + +void eve_pagew_init(EVEPageWidget *widget, EVERect *g, char *title, EVEFont *font, EVEPage *page) { + EVEWidget *_widget = &widget->w; + + memset(widget, 0, sizeof(EVEPageWidget)); + eve_widget_init(_widget, EVE_WIDGET_TYPE_PAGE, g, eve_pagew_touch, eve_pagew_draw, NULL); + widget->title = title; + widget->font = font; + widget->page = page; + if (_widget->g.w == 0) _widget->g.w = eve_font_str_w(font, widget->title); + if (_widget->g.h == 0) _widget->g.h = eve_font_h(font); +} + +int eve_pagew_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) { + EVEPageWidget *widget = (EVEPageWidget *)_widget; + EVETouch *t; + uint16_t evt; + int ret = 0; + + if (touch_idx > 0) return 0; + + t = eve_touch_evt(tag0, touch_idx, widget->tag, 1, &evt); + if (t && evt) { + if (evt & EVE_TOUCH_ETYPE_TRACK_MASK) { + if (page && page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx); + } else if (evt & EVE_TOUCH_ETYPE_TAG_UP) { + widget->page->open(widget->page, page); + } + ret = 1; + } + return ret; +} + +uint8_t eve_pagew_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) { + EVEPageWidget *widget = (EVEPageWidget *)_widget; + + widget->tag = tag0; + if (tag0 != EVE_TAG_NOTAG) { + eve_cmd_dl(TAG(tag0)); + tag0++; + } + eve_cmd(CMD_TEXT, "hhhhs", _widget->g.x, _widget->g.y, widget->font->id, 0, widget->title); + + return tag0; +} diff --git a/fw/fe310/eos/eve/widget/pagew.h b/fw/fe310/eos/eve/widget/pagew.h new file mode 100644 index 0000000..1f9ae18 --- /dev/null +++ b/fw/fe310/eos/eve/widget/pagew.h @@ -0,0 +1,13 @@ +#include <stdint.h> + +typedef struct EVEPageWidget { + EVEWidget w; + char *title; + EVEFont *font; + EVEPage *page; + uint8_t tag; +} EVEPageWidget; + +void eve_pagew_init(EVEPageWidget *widget, EVERect *g, char *title, EVEFont *font, EVEPage *page); +int eve_pagew_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx); +uint8_t eve_pagew_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0); diff --git a/fw/fe310/eos/eve/widget/strw.c b/fw/fe310/eos/eve/widget/strw.c new file mode 100644 index 0000000..2a80a28 --- /dev/null +++ b/fw/fe310/eos/eve/widget/strw.c @@ -0,0 +1,418 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen/screen.h" +#include "screen/window.h" +#include "screen/page.h" +#include "screen/font.h" + +#include "clipb.h" +#include "label.h" +#include "widget.h" +#include "strw.h" + +#define CH_BS 0x08 +#define CH_DEL 0x7f +#define CH_EOF 0x1a + +#define CH_CTRLX 0x18 +#define CH_CTRLC 0x03 +#define CH_CTRLV 0x16 + +#define STRW_TMODE_CURSOR 1 +#define STRW_TMODE_SCROLL_X 2 +#define STRW_TMODE_SCROLL_Y 3 + +#define CHAR_VALID_INPUT(c) ((c >= 0x20) && (c < 0x7f)) + +void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, utf8_t *str, uint16_t str_size) { + int rv, str_len; + EVEWidget *_widget = &widget->w; + + memset(widget, 0, sizeof(EVEStrWidget)); + eve_widget_init(_widget, EVE_WIDGET_TYPE_STR, g, eve_strw_touch, eve_strw_draw, eve_strw_putc); + widget->font = font; + widget->str = str; + widget->str_size = str_size; + rv = utf8_verify(str, str_size, &str_len); + if (rv != UTF_OK) { + if (str_len >= str_size) str_len = 0; + widget->str[str_len] = '\0'; + } + widget->str_len = str_len; + widget->str_g.w = eve_font_str_w(font, str); + if (_widget->g.h == 0) _widget->g.h = eve_font_h(font); +} + +static void set_focus(EVEStrWidget *widget, EVEPage *page) { + EVERect focus; + EVEWidget *_widget = &widget->w; + + focus.x = _widget->g.x; + focus.y = _widget->g.y; + focus.w = _widget->g.w; + focus.h = 2 * widget->font->h; + eve_page_set_focus(page, _widget, &focus); +} + +static EVEStrCursor *cursor_prox(EVEStrWidget *widget, EVEStrCursor *cursor, EVEPage *page, EVETouch *t, short *dx) { + EVEWidget *_widget = &widget->w; + int x = eve_page_x(page, t->x0) - _widget->g.x + widget->str_g.x; + int _dx; + + *dx = cursor->x - x; + _dx = *dx < 0 ? -(*dx) : *dx; + + if (_dx <= widget->font->w) return cursor; + return NULL; +} + +int eve_strw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) { + EVEStrWidget *widget = (EVEStrWidget *)_widget; + EVETouch *t; + uint16_t evt; + + if (touch_idx > 0) return 0; + + t = eve_touch_evt(tag0, touch_idx, widget->tag, 1, &evt); + if (t && evt) { + EVEStrCursor *t_cursor = NULL; + short dx; + + if (evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TRACK_START)) { + if (widget->cursor2.on) { + t_cursor = cursor_prox(widget, &widget->cursor2, page, t, &dx); + } + if ((t_cursor == NULL) && widget->cursor1.on) { + t_cursor = cursor_prox(widget, &widget->cursor1, page, t, &dx); + } + if (evt & EVE_TOUCH_ETYPE_TRACK_START) { + widget->track.cursor = t_cursor; + if (t_cursor) { + widget->track.mode = STRW_TMODE_CURSOR; + widget->track.dx = dx; + } else if (t->eevt & EVE_TOUCH_EETYPE_TRACK_X) { + widget->track.mode = STRW_TMODE_SCROLL_X; + } else if (t->eevt & EVE_TOUCH_EETYPE_TRACK_Y) { + widget->track.mode = STRW_TMODE_SCROLL_Y; + } + } + } + + switch (widget->track.mode) { + case STRW_TMODE_SCROLL_Y: + if (page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx); + break; + + case STRW_TMODE_SCROLL_X: + if (evt & EVE_TOUCH_ETYPE_TRACK_START) { + widget->str_g.x0 = widget->str_g.x; + } + if (evt & EVE_TOUCH_ETYPE_TRACK) { + int x = widget->str_g.x0 + t->x0 - t->x; + int w1 = widget->w.g.w - widget->font->w; + + if (x > widget->str_g.w - w1) x = widget->str_g.w - w1; + if (x < 0) x = 0; + widget->str_g.x = x; + } + break; + + case STRW_TMODE_CURSOR: + if (evt & EVE_TOUCH_ETYPE_TRACK) eve_strw_cursor_set(widget, widget->track.cursor, eve_page_x(page, t->x) + widget->track.dx); + break; + + default: + if (evt & EVE_TOUCH_ETYPE_LPRESS) { + if (widget->cursor2.on) { + // copy + } else if (widget->cursor1.on) { + if (t_cursor) { + // paste + } else { + eve_strw_cursor_set(widget, &widget->cursor2, eve_page_x(page, t->x)); + } + } else { + // select + } + } + if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(t->eevt & EVE_TOUCH_EETYPE_LPRESS)) { + eve_strw_cursor_set(widget, &widget->cursor1, eve_page_x(page, t->x0)); + if (widget->cursor2.on) eve_strw_cursor_clear(widget, &widget->cursor2); + set_focus(widget, page); + } + break; + } + + if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) { + widget->track.mode = 0; + widget->track.cursor = NULL; + widget->track.dx = 0; + } + + return 1; + } + + return 0; +} + +static void _draw_str(EVEStrWidget *widget, EVEWindow *window, uint16_t ch, uint16_t len, uint16_t x1, uint16_t x2, char s) { + int16_t x; + EVEWidget *_widget = &widget->w; + + x = _widget->g.x - widget->str_g.x; + if (x1 != x2) { + eve_cmd_dl(BEGIN(EVE_RECTS)); + if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0)); + eve_cmd_dl(VERTEX2F(x + x1, _widget->g.y)); + eve_cmd_dl(VERTEX2F(x + x2, _widget->g.y + widget->font->h)); + if (!s) eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1)); + eve_cmd_dl(END()); + if (len) { + if (s) eve_cmd_dl(COLOR_RGBC(window->color_bg)); + eve_cmd(CMD_TEXT, "hhhhpb", x + x1, _widget->g.y, widget->font->id, 0, widget->str + ch, len, 0); + if (s) eve_cmd_dl(COLOR_RGBC(window->color_fg)); + } + } +} + +static void _draw_cursor(EVEStrWidget *widget, EVEStrCursor *cursor) { + uint16_t x, y; + EVEWidget *_widget = &widget->w; + + x = _widget->g.x - widget->str_g.x + cursor->x; + y = _widget->g.y; + eve_cmd_dl(BEGIN(EVE_LINES)); + eve_cmd_dl(VERTEX2F(x, y)); + eve_cmd_dl(VERTEX2F(x, y + widget->font->h)); + eve_cmd_dl(END()); +} + +uint8_t eve_strw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) { + EVEStrWidget *widget = (EVEStrWidget *)_widget; + char cut = widget->str_g.x || (widget->str_g.w > _widget->g.w); + + widget->tag = tag0; + if (tag0 != EVE_TAG_NOTAG) { + eve_cmd_dl(TAG(tag0)); + eve_touch_set_opt(tag0, EVE_TOUCH_OPT_LPRESS); + tag0++; + } + + if (cut) { + EVEWindow *window = page->v.window; + EVEScreen *screen = window->screen; + int16_t x = eve_page_scr_x(page, _widget->g.x); + int16_t y = eve_page_scr_y(page, _widget->g.y); + uint16_t w = _widget->g.w; + uint16_t h = _widget->g.h; + int16_t win_x1 = window->g.x; + int16_t win_y1 = window->g.y; + int16_t win_x2 = win_x1 + window->g.w; + int16_t win_y2 = win_y1 + window->g.h; + + if (win_x1 < 0) win_x1 = 0; + if (win_y1 < 0) win_y1 = 0; + if (win_x2 > screen->w) win_x2 = screen->w; + if (win_y2 > screen->h) win_y2 = screen->h; + if (x < win_x1) { + w += x - win_x1; + x = win_x1; + } + if (y < win_y1) { + h += y - win_y1; + y = win_y1; + } + if (x + w > win_x2) w = win_x2 - x; + if (y + h > win_y2) h = win_y2 - y; + + eve_cmd_dl(SAVE_CONTEXT()); + eve_cmd_dl(SCISSOR_XY(x, y)); + eve_cmd_dl(SCISSOR_SIZE(w, h)); + } + + if (widget->cursor2.on) { + EVEStrCursor *c1, *c2; + int l1, l2, l3; + + if (widget->cursor1.ch <= widget->cursor2.ch) { + c1 = &widget->cursor1; + c2 = &widget->cursor2; + } else { + c1 = &widget->cursor2; + c2 = &widget->cursor1; + } + + l1 = c1->ch; + l2 = c2->ch - c1->ch; + l3 = widget->str_len - c2->ch; + _draw_str(widget, page->v.window, 0, l1, 0, c1->x, 0); + _draw_str(widget, page->v.window, c1->ch, l2, c1->x, c2->x, 1); + _draw_str(widget, page->v.window, c2->ch, l3, c2->x, widget->str_g.x + _widget->g.w, 0); + } else { + if (widget->cursor1.on) _draw_cursor(widget, &widget->cursor1); + _draw_str(widget, page->v.window, 0, widget->str_len, 0, widget->str_g.x + _widget->g.w, 0); + } + + if (cut) { + eve_cmd_dl(RESTORE_CONTEXT()); + } + + return tag0; +} + +void eve_strw_putc(void *_page, int c) { + EVEPage *page = _page; + EVEStrWidget *widget = (EVEStrWidget *)eve_page_get_focus(page); + EVEStrCursor *cursor1 = &widget->cursor1; + EVEStrCursor *cursor2 = &widget->cursor2; + utf8_t *str; + utf8_t *clipb = NULL; + int w0 = widget->font->w; + int w1 = widget->w.g.w - widget->font->w; + int ins_c = 0, del_c = 0; + int ins_w = 0, del_w = 0; + + + if (c == CH_EOF) { + if (cursor1->on) eve_strw_cursor_clear(widget, cursor1); + if (cursor2->on) eve_strw_cursor_clear(widget, cursor2); + return; + } + + if (!cursor1->on) return; + + if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) { + utf32_t uc; + + str = widget->str + cursor1->ch; + switch (c) { + case CH_BS: + if (cursor1->ch > 0) { + del_c = -utf8_seek(str, -1, &uc); + del_w = eve_font_ch_w(widget->font, uc); + memmove(str - del_c, str, widget->str_len - cursor1->ch + 1); + widget->str_len -= del_c; + widget->str_g.w -= del_w; + cursor1->ch -= del_c; + cursor1->x -= del_w; + } + break; + + case CH_DEL: + if (cursor1->ch < widget->str_len) { + del_c = utf8_dec(str, &uc); + del_w = eve_font_ch_w(widget->font, uc); + memmove(str, str + del_c, widget->str_len - cursor1->ch - del_c + 1); + widget->str_len -= del_c; + widget->str_g.w -= del_w; + } + break; + } + if (widget->str_g.w - widget->str_g.x < w1) { + widget->str_g.x -= del_w; + if (widget->str_g.x < 0) widget->str_g.x = 0; + } + } else { + EVEStrCursor *c1 = cursor1; + EVEStrCursor *c2 = cursor1; + utf8_t utf8_buf[4]; + + if (cursor2->on) { + if (cursor1->ch <= cursor2->ch) { + c2 = cursor2; + } else { + c1 = cursor2; + } + del_c = c2->ch - c1->ch; + del_w = eve_font_buf_w(widget->font, str, del_c); + if ((c == CH_CTRLX) || (c == CH_CTRLC)) { + eve_clipb_push(str, del_c); + if (c == CH_CTRLC) return; + } + } + + str = widget->str + c1->ch; + if (CHAR_VALID_INPUT(c)) { + ins_c = utf8_enc(c, utf8_buf); + ins_w = eve_font_ch_w(widget->font, c); + } else if (c == CH_CTRLV) { + int rv, clipb_len = 0; + + clipb = eve_clipb_get(); + if (clipb) { + rv = utf8_verify(clipb, EVE_CLIPB_SIZE_BUF, &clipb_len); + if (rv != UTF_OK) { + clipb = NULL; + clipb_len = 0; + } + } + ins_c = clipb_len; + ins_w = eve_font_str_w(widget->font, clipb); + } + if (widget->str_len + ins_c >= widget->str_size + del_c) { + ins_c = 0; + ins_w = 0; + } + if (ins_c != del_c) memmove(str + ins_c, str + del_c, widget->str_len - c2->ch + 1); + if (ins_c) { + if (c == CH_CTRLV) { + memcpy(str, clipb, ins_c); + } else if (ins_c > 1) { + memcpy(str, utf8_buf, ins_c); + } else { + *str = utf8_buf[0]; + } + c1->ch += ins_c; + c1->x += ins_w; + } + widget->str_len += ins_c - del_c; + widget->str_g.w += ins_w - del_w; + if (c1 == cursor2) widget->cursor1 = widget->cursor2; + if (cursor2->on) eve_strw_cursor_clear(widget, cursor2); + } + + if (cursor1->x - widget->str_g.x < w0) widget->str_g.x = cursor1->x > w0 ? cursor1->x - w0 : 0; + if (cursor1->x - widget->str_g.x > w1) widget->str_g.x = cursor1->x - w1; +} + +void eve_strw_cursor_set(EVEStrWidget *widget, EVEStrCursor *cursor, int16_t x) { + int i; + int16_t _x, _d; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + EVEWidget *_widget = &widget->w; + + x = x - _widget->g.x + widget->str_g.x; + + _x = 0; + _d = x; + i = 0; + while (i < widget->str_len) { + ch_l = utf8_dec(widget->str + i, &ch); + ch_w = eve_font_ch_w(widget->font, ch); + _x += ch_w; + i += ch_l; + if (_x >= x) { + if (_x - x > _d) { + _x -= ch_w; + i -= ch_l; + } + break; + } else { + _d = x - _x; + } + } + cursor->x = _x; + cursor->ch = i; + cursor->on = 1; +} + +void eve_strw_cursor_clear(EVEStrWidget *widget, EVEStrCursor *cursor) { + cursor->on = 0; +} diff --git a/fw/fe310/eos/eve/widget/strw.h b/fw/fe310/eos/eve/widget/strw.h new file mode 100644 index 0000000..72fc6aa --- /dev/null +++ b/fw/fe310/eos/eve/widget/strw.h @@ -0,0 +1,35 @@ +#include <stdint.h> + +typedef struct EVEStrCursor { + char on; + uint16_t x; + uint16_t ch; +} EVEStrCursor; + +typedef struct EVEStrWidget { + EVEWidget w; + EVEFont *font; + utf8_t *str; + uint16_t str_size; + uint16_t str_len; + struct { + int16_t x; + int16_t x0; + uint16_t w; + } str_g; + EVEStrCursor cursor1; + EVEStrCursor cursor2; + uint8_t tag; + struct { + EVEStrCursor *cursor; + short dx; + char mode; + } track; +} EVEStrWidget; + +void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, utf8_t *str, uint16_t str_size); +int eve_strw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx); +uint8_t eve_strw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0); +void eve_strw_putc(void *_page, int c); +void eve_strw_cursor_set(EVEStrWidget *widget, EVEStrCursor *cursor, int16_t x); +void eve_strw_cursor_clear(EVEStrWidget *widget, EVEStrCursor *cursor);
\ No newline at end of file diff --git a/fw/fe310/eos/eve/widget/textw.c b/fw/fe310/eos/eve/widget/textw.c new file mode 100644 index 0000000..bf075cf --- /dev/null +++ b/fw/fe310/eos/eve/widget/textw.c @@ -0,0 +1,535 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen/screen.h" +#include "screen/window.h" +#include "screen/page.h" +#include "screen/font.h" + +#include "clipb.h" +#include "label.h" +#include "widget.h" +#include "textw.h" + +#define CH_BS 0x08 +#define CH_DEL 0x7f +#define CH_EOF 0x1a + +#define CH_CTRLX 0x18 +#define CH_CTRLC 0x03 +#define CH_CTRLV 0x16 + +#define TEXTW_TMODE_CURSOR 1 +#define TEXTW_TMODE_SCROLL 2 + +#define LINE_LEN(w,l) ((l) ? (w->line[l] ? w->line[l] - w->line[(l) - 1] - 1 : 0) : w->line[l]) +#define LINE_START(w,l) ((l) ? w->line[(l) - 1] + 1 : 0) +#define LINE_END(w,l) (w->line[l]) +#define LINE_EMPTY 0xffff + +#define CHAR_VALID_INPUT(c) (((c >= 0x20) && (c < 0x7f)) || (c == '\n')) + +#define DIVC(x,y) ((x) / (y) + ((x) % (y) != 0)) + +void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size) { + int rv, text_len; + EVEWidget *_widget = &widget->w; + + memset(widget, 0, sizeof(EVETextWidget)); + eve_widget_init(_widget, EVE_WIDGET_TYPE_TEXT, g, eve_textw_touch, eve_textw_draw, eve_textw_putc); + widget->font = font; + widget->text = text; + widget->text_size = text_size; + rv = utf8_verify(text, text_size, &text_len); + if (rv != UTF_OK) { + if (text_len >= text_size) text_len = 0; + widget->text[text_len] = '\0'; + } + widget->text_len = text_len; + widget->line = line; + widget->line_size = line_size; + memset(widget->line, 0xff, line_size * sizeof(uint16_t)); + eve_textw_update(widget, NULL, 0); +} + +static void set_focus(EVETextWidget *widget, EVETextCursor *cursor, EVEPage *page) { + EVERect focus; + EVEWidget *_widget = &widget->w; + + focus.x = _widget->g.x; + focus.y = _widget->g.y + cursor->line * widget->font->h; + focus.w = _widget->g.w; + focus.h = 2 * widget->font->h; + eve_page_set_focus(page, _widget, &focus); +} + +static EVETextCursor *cursor_prox(EVETextWidget *widget, EVETextCursor *cursor, EVEPage *page, EVETouch *t, short *dx, short *dl) { + EVEWidget *_widget = &widget->w; + int x = eve_page_x(page, t->x0) - _widget->g.x; + int l = (int)t->tag0 - widget->tag0 + widget->line0; + int _dx, _dl; + + *dx = cursor->x - x; + *dl = cursor->line - l; + + _dx = *dx < 0 ? -(*dx) : *dx; + _dl = *dl < 0 ? -(*dl) : *dl; + + if ((_dx <= widget->font->h) && (_dl <= 1)) return cursor; + return NULL; +} + +int eve_textw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) { + EVETextWidget *widget = (EVETextWidget *)_widget; + EVETouch *t; + uint16_t evt; + int ret = 0; + + if (touch_idx > 0) return 0; + + t = eve_touch_evt(tag0, touch_idx, widget->tag0, widget->tagN - widget->tag0, &evt); + if (t && evt) { + EVETextCursor *t_cursor = NULL; + short dx, dl; + + if (evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TRACK_START)) { + if (widget->cursor2.on) { + t_cursor = cursor_prox(widget, &widget->cursor2, page, t, &dx, &dl); + } + if ((t_cursor == NULL) && widget->cursor1.on) { + t_cursor = cursor_prox(widget, &widget->cursor1, page, t, &dx, &dl); + } + if (evt & EVE_TOUCH_ETYPE_TRACK_START) { + widget->track.cursor = t_cursor; + if (t_cursor) { + widget->track.mode = TEXTW_TMODE_CURSOR; + widget->track.dx = dx; + widget->track.dl = dl; + } else { + widget->track.mode = TEXTW_TMODE_SCROLL; + } + } + } + + switch (widget->track.mode) { + case TEXTW_TMODE_SCROLL: + if (page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx); + break; + + case TEXTW_TMODE_CURSOR: + if (evt & EVE_TOUCH_ETYPE_TRACK) eve_textw_cursor_set(widget, widget->track.cursor, t->tag + widget->track.dl, eve_page_x(page, t->x) + widget->track.dx); + break; + + default: + if (evt & EVE_TOUCH_ETYPE_LPRESS) { + if (widget->cursor2.on) { + // copy + } else if (widget->cursor1.on) { + if (t_cursor && (dl == 0)) { + // paste + } else { + eve_textw_cursor_set(widget, &widget->cursor2, t->tag, eve_page_x(page, t->x)); + } + } else { + // select + } + } + if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(t->eevt & EVE_TOUCH_EETYPE_LPRESS)) { + eve_textw_cursor_set(widget, &widget->cursor1, t->tag_up, eve_page_x(page, t->x0)); + if (widget->cursor2.on) eve_textw_cursor_clear(widget, &widget->cursor2); + set_focus(widget, &widget->cursor1, page); + } + break; + } + + if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) { + widget->track.mode = 0; + widget->track.cursor = NULL; + widget->track.dx = 0; + widget->track.dl = 0; + } + + ret = 1; + } + + return ret; +} + +static void _draw_line(EVETextWidget *widget, EVEWindow *window, uint16_t l, uint16_t ch, uint16_t len, uint16_t x1, uint16_t x2, char s) { + EVEWidget *_widget = &widget->w; + + if (x1 != x2) { + eve_cmd_dl(BEGIN(EVE_RECTS)); + if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0)); + eve_cmd_dl(VERTEX2F(_widget->g.x + x1, _widget->g.y + l * widget->font->h)); + eve_cmd_dl(VERTEX2F(_widget->g.x + x2, _widget->g.y + (l + 1) * widget->font->h)); + if (!s) eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1)); + eve_cmd_dl(END()); + if (len) { + if (s) eve_cmd_dl(COLOR_RGBC(window->color_bg)); + eve_cmd(CMD_TEXT, "hhhhpb", _widget->g.x + x1, _widget->g.y + l * widget->font->h, widget->font->id, 0, widget->text + ch, len, 0); + if (s) eve_cmd_dl(COLOR_RGBC(window->color_fg)); + } + } +} + +static void _draw_cursor(EVETextWidget *widget, EVETextCursor *cursor) { + uint16_t x, y; + EVEWidget *_widget = &widget->w; + + x = _widget->g.x + cursor->x; + y = _widget->g.y + cursor->line * widget->font->h; + eve_cmd_dl(BEGIN(EVE_LINES)); + eve_cmd_dl(VERTEX2F(x, y)); + eve_cmd_dl(VERTEX2F(x, y + widget->font->h)); + eve_cmd_dl(END()); +} + +uint8_t eve_textw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) { + EVETextWidget *widget = (EVETextWidget *)_widget; + int line0, lineN; + int _line0, _lineN; + char lineNvisible; + + _line0 = line0 = ((int)page->win_y - _widget->g.y) / widget->font->h; + _lineN = lineN = DIVC(((int)page->win_y - _widget->g.y + page->v.window->g.h), widget->font->h); + if (line0 < 0) line0 = 0; + if (lineN < 0) lineN = 0; + if (line0 > widget->line_len) line0 = widget->line_len; + if (lineN > widget->line_len) lineN = widget->line_len; + lineNvisible = (lineN >= _line0) && (lineN < _lineN); + + if (lineNvisible || (line0 < lineN)) { + int i; + char s = 0; + EVETextCursor *c1, *c2; + + widget->line0 = line0; + widget->tag0 = tag0; + widget->tagN = tag0; + + if (widget->cursor2.on) { + if (widget->cursor1.ch <= widget->cursor2.ch) { + c1 = &widget->cursor1; + c2 = &widget->cursor2; + } else { + c1 = &widget->cursor2; + c2 = &widget->cursor1; + } + } else { + c1 = NULL; + c2 = NULL; + } + + for (i=line0; i<lineN; i++) { + if (widget->tagN != EVE_TAG_NOTAG) { + eve_cmd_dl(TAG(widget->tagN)); + eve_touch_set_opt(widget->tagN, EVE_TOUCH_OPT_LPRESS); + widget->tagN++; + } + if (!s && c1 && (c1->line == i)) { + int l1, l2, l3; + + l1 = c1->ch - LINE_START(widget, i); + if (c2->line == i) { + l2 = c2->ch - c1->ch; + l3 = LINE_START(widget, i) + LINE_LEN(widget, i) - c2->ch; + } else { + l2 = LINE_START(widget, i) + LINE_LEN(widget, i) - c1->ch; + l3 = 0; + s = 1; + } + _draw_line(widget, page->v.window, i, LINE_START(widget, i), l1, 0, c1->x, 0); + _draw_line(widget, page->v.window, i, c1->ch, l2, c1->x, s ? _widget->g.w : c2->x, 1); + if (!s) { + _draw_line(widget, page->v.window, i, c2->ch, l3, c2->x, _widget->g.w, 0); + c1 = NULL; + c2 = NULL; + } + } else if (s && (c2->line == i)) { + int l1 = c2->ch - LINE_START(widget, i); + int l2 = LINE_START(widget, i) + LINE_LEN(widget, i) - c2->ch; + + _draw_line(widget, page->v.window, i, LINE_START(widget, i), l1, 0, c2->x, 1); + _draw_line(widget, page->v.window, i, c2->ch, l2, c2->x, _widget->g.w, 0); + c1 = NULL; + c2 = NULL; + s = 0; + } else { + if (widget->cursor1.on && (widget->cursor1.line == i)) _draw_cursor(widget, &widget->cursor1); + _draw_line(widget, page->v.window, i, LINE_START(widget, i), LINE_LEN(widget, i), 0, _widget->g.w, s); + } + } + if (lineNvisible) { + if (widget->tagN != EVE_TAG_NOTAG) { + eve_cmd_dl(TAG(widget->tagN)); + eve_touch_set_opt(widget->tagN, EVE_TOUCH_OPT_LPRESS); + widget->tagN++; + } + _draw_line(widget, page->v.window, lineN, 0, 0, 0, _widget->g.w, 0); + } + + return widget->tagN; + } else { + widget->line0 = 0; + widget->tag0 = EVE_TAG_NOTAG; + widget->tagN = EVE_TAG_NOTAG; + + return tag0; + } +} + +void eve_textw_putc(void *_page, int c) { + EVEPage *page = _page; + EVETextWidget *widget = (EVETextWidget *)eve_page_get_focus(page); + EVETextCursor *cursor1 = &widget->cursor1; + EVETextCursor *cursor2 = &widget->cursor2; + utf8_t *text; + utf8_t *clipb = NULL; + int i, r; + int ins_c = 0, del_c = 0; + int ch_w = 0; + + if (c == CH_EOF) { + if (cursor1->on) eve_textw_cursor_clear(widget, cursor1); + if (cursor2->on) eve_textw_cursor_clear(widget, cursor2); + return; + } + + if (!cursor1->on) return; + + if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) { + utf32_t uc; + + text = widget->text + cursor1->ch; + switch (c) { + case CH_BS: + if (cursor1->ch > 0) { + del_c = -utf8_seek(text, -1, &uc); + ch_w = eve_font_ch_w(widget->font, uc); + memmove(text - del_c, text, widget->text_len - cursor1->ch + 1); + cursor1->ch -= del_c; + } + break; + + case CH_DEL: + if (cursor1->ch < widget->text_len) { + del_c = utf8_dec(text, &uc); + ch_w = eve_font_ch_w(widget->font, uc); + memmove(text, text + del_c, widget->text_len - cursor1->ch - del_c + 1); + } + break; + } + } else { + EVETextCursor *c1 = cursor1; + EVETextCursor *c2 = cursor1; + utf8_t utf8_buf[4]; + + if (cursor2->on) { + if (cursor1->ch <= cursor2->ch) { + c2 = cursor2; + } else { + c1 = cursor2; + } + del_c = c2->ch - c1->ch; + if ((c == CH_CTRLX) || (c == CH_CTRLC)) { + eve_clipb_push(text, del_c); + if (c == CH_CTRLC) return; + } + } + + text = widget->text + c1->ch; + if (CHAR_VALID_INPUT(c)) { + ins_c = utf8_enc(c, utf8_buf); + ch_w = eve_font_ch_w(widget->font, c); + } else if (c == CH_CTRLV) { + int rv, clipb_len = 0; + + clipb = eve_clipb_get(); + if (clipb) { + rv = utf8_verify(clipb, EVE_CLIPB_SIZE_BUF, &clipb_len); + if (rv != UTF_OK) { + clipb = NULL; + clipb_len = 0; + } + } + ins_c = clipb_len; + ch_w = eve_font_str_w(widget->font, clipb); + } + if (widget->text_len + ins_c >= widget->text_size + del_c) { + ins_c = 0; + ch_w = 0; + } + if (ins_c != del_c) memmove(text + ins_c, text + del_c, widget->text_len - c2->ch + 1); + if (ins_c) { + if (c == CH_CTRLV) { + memcpy(text, clipb, ins_c); + } else if (ins_c > 1) { + memcpy(text, utf8_buf, ins_c); + } else { + *text = utf8_buf[0]; + } + c1->ch += ins_c; + } + if (c1 == cursor2) widget->cursor1 = widget->cursor2; + if (cursor2->on) eve_textw_cursor_clear(widget, cursor2); + } + + if ((ins_c == 0) && (del_c == 0)) return; + + widget->text_len += ins_c - del_c; + for (i=cursor1->line; i<widget->line_len; i++) { + widget->line[i] += ins_c - del_c; + } + + r = cursor1->line; + if (cursor1->line) r = eve_textw_update(widget, page, cursor1->line - 1); + if ((cursor1->line == 0) || (r == cursor1->line - 1)) r = eve_textw_update(widget, page, cursor1->line); + + if (cursor1->line && (cursor1->ch < LINE_START(widget, cursor1->line))) { + cursor1->line--; + eve_textw_cursor_update(widget, cursor1); + set_focus(widget, cursor1, page); + } else if (cursor1->ch > LINE_END(widget, cursor1->line)) { + while (cursor1->ch > LINE_END(widget, cursor1->line)) cursor1->line++; + eve_textw_cursor_update(widget, cursor1); + set_focus(widget, cursor1, page); + } else { + cursor1->x += ch_w; + } +} + +uint16_t eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { + int i; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + uint16_t word_w, line_w, line_b; + uint16_t new_h; + EVEWidget *_widget = &widget->w; + + word_w = 0; + line_w = 0; + line_b = LINE_EMPTY; + + i = LINE_START(widget, line); + while (i < widget->text_size) { + ch_l = utf8_dec(widget->text + i, &ch); + if (!CHAR_VALID_INPUT(ch) && ch) { + ch = 0; + widget->text[i] = '\0'; + widget->text_len = i; + widget->line[line] = LINE_EMPTY; + } + + ch_w = eve_font_ch_w(widget->font, ch); + if (ch <= 0x20) { + if ((ch == '\n') || (ch == '\0')) { + if (widget->line[line] == i) return line; + widget->line[line] = i; + line++; + if ((ch == '\0') || (line == widget->line_size)) break; + word_w = 0; + line_w = 0; + line_b = LINE_EMPTY; + } else if (ch == ' ') { + word_w = 0; + line_w += ch_w; + line_b = i; + } + } else { + word_w += ch_w; + line_w += ch_w; + } + if ((line_w > _widget->g.w) && (line_b != LINE_EMPTY)) { + if (widget->line[line] == line_b) return line; + widget->line[line] = line_b; + line++; + if (line == widget->line_size) { + i = line_b; + break; + } + line_w = word_w; + line_b = LINE_EMPTY; + } + i += ch_l; + } + + widget->line_len = line; + new_h = (line + 1) * widget->font->h; + for (i=line; i<widget->line_size; i++) { + widget->line[i] = LINE_EMPTY; + } + + if (_widget->g.h != new_h) { + _widget->g.h = new_h; + if (page && page->update_g) page->update_g(page, _widget); + } + + return line; +} + +void eve_textw_cursor_update(EVETextWidget *widget, EVETextCursor *cursor) { + int i = LINE_START(widget, cursor->line); + uint16_t x = 0; + utf32_t ch; + uint8_t ch_l; + + while ((i < cursor->ch) && (i < LINE_END(widget, cursor->line))) { + ch_l = utf8_dec(widget->text + i, &ch); + x += eve_font_ch_w(widget->font, ch); + i += ch_l; + } + cursor->x = x; +} + +void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t tag, int16_t x) { + int i; + int16_t _x, _d; + uint16_t c_line = LINE_EMPTY; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + EVEWidget *_widget = &widget->w; + + if ((tag >= widget->tag0) && ((widget->tagN == EVE_TAG_NOTAG) || (tag < widget->tagN))) c_line = tag - widget->tag0 + widget->line0; + if (c_line < widget->line_len) { + cursor->line = c_line; + } else if (c_line == widget->line_len) { + cursor->line = c_line - 1; + } else if (!cursor->on) { + return; + } + + x -= _widget->g.x; + + _x = 0; + _d = x; + i = LINE_START(widget, cursor->line); + while (i < LINE_END(widget, cursor->line)) { + ch_l = utf8_dec(widget->text + i, &ch); + ch_w = eve_font_ch_w(widget->font, ch); + _x += ch_w; + i += ch_l; + if (_x >= x) { + if (_x - x > _d) { + _x -= ch_w; + i -= ch_l; + } + break; + } else { + _d = x - _x; + } + } + cursor->x = _x; + cursor->ch = i; + cursor->on = 1; +} + +void eve_textw_cursor_clear(EVETextWidget *widget, EVETextCursor *cursor) { + cursor->on = 0; +} diff --git a/fw/fe310/eos/eve/widget/textw.h b/fw/fe310/eos/eve/widget/textw.h new file mode 100644 index 0000000..cd46ea3 --- /dev/null +++ b/fw/fe310/eos/eve/widget/textw.h @@ -0,0 +1,39 @@ +#include <stdint.h> + +typedef struct EVETextCursor { + char on; + uint16_t x; + uint16_t line; + uint16_t ch; +} EVETextCursor; + +typedef struct EVETextWidget { + EVEWidget w; + EVEFont *font; + utf8_t *text; + uint16_t text_size; + uint16_t text_len; + uint16_t *line; + uint16_t line_size; + uint16_t line_len; + EVETextCursor cursor1; + EVETextCursor cursor2; + uint16_t line0; + uint8_t tag0; + uint8_t tagN; + struct { + EVETextCursor *cursor; + short dx; + short dl; + char mode; + } track; +} EVETextWidget; + +void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size); +int eve_textw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx); +uint8_t eve_textw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0); +void eve_textw_putc(void *_w, int c); +uint16_t eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line); +void eve_textw_cursor_update(EVETextWidget *widget, EVETextCursor *cursor); +void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t tag, int16_t x); +void eve_textw_cursor_clear(EVETextWidget *widget, EVETextCursor *cursor); diff --git a/fw/fe310/eos/eve/widget/widget.c b/fw/fe310/eos/eve/widget/widget.c new file mode 100644 index 0000000..ab121d8 --- /dev/null +++ b/fw/fe310/eos/eve/widget/widget.c @@ -0,0 +1,41 @@ +#include <stdlib.h> +#include <string.h> + +#include "eve.h" +#include "eve_kbd.h" +#include "unicode.h" + +#include "screen/screen.h" +#include "screen/window.h" +#include "screen/page.h" +#include "screen/font.h" + +#include "label.h" +#include "widget.h" +#include "pagew.h" +#include "strw.h" +#include "textw.h" + +static const size_t _eve_wsize[] = { + 0, + sizeof(EVEPageWidget), + sizeof(EVEStrWidget), + sizeof(EVETextWidget) +}; + +void eve_widget_init(EVEWidget *widget, uint8_t type, EVERect *g, eve_widget_touch_t touch, eve_widget_draw_t draw, eve_kbd_input_handler_t putc) { + if (g) widget->g = *g; + widget->touch = touch; + widget->draw = draw; + widget->putc = putc; + widget->type = type; +} + +void eve_widget_set_label(EVEWidget *widget, EVELabel *label) { + widget->label = label; +} + +EVEWidget *eve_widget_next(EVEWidget *widget) { + char *_w = (char *)widget; + return (EVEWidget *)(_w + _eve_wsize[widget->type]); +} diff --git a/fw/fe310/eos/eve/widget/widget.h b/fw/fe310/eos/eve/widget/widget.h new file mode 100644 index 0000000..1aa2cd7 --- /dev/null +++ b/fw/fe310/eos/eve/widget/widget.h @@ -0,0 +1,23 @@ +#include <stdint.h> + +#define EVE_WIDGET_TYPE_PAGE 1 +#define EVE_WIDGET_TYPE_STR 2 +#define EVE_WIDGET_TYPE_TEXT 3 + +struct EVEWidget; + +typedef int (*eve_widget_touch_t) (struct EVEWidget *, EVEPage *, uint8_t, int); +typedef uint8_t (*eve_widget_draw_t) (struct EVEWidget *, EVEPage *, uint8_t); + +typedef struct EVEWidget { + EVERect g; + eve_widget_touch_t touch; + eve_widget_draw_t draw; + eve_kbd_input_handler_t putc; + EVELabel *label; + uint8_t type; +} EVEWidget; + +void eve_widget_init(EVEWidget *widget, uint8_t type, EVERect *g, eve_widget_touch_t touch, eve_widget_draw_t draw, eve_kbd_input_handler_t putc); +void eve_widget_set_label(EVEWidget *widget, EVELabel *label); +EVEWidget *eve_widget_next(EVEWidget *widget); diff --git a/fw/fe310/eos/event.c b/fw/fe310/eos/event.c new file mode 100644 index 0000000..6953dca --- /dev/null +++ b/fw/fe310/eos/event.c @@ -0,0 +1,138 @@ +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <stdio.h> + +#include "encoding.h" +#include "platform.h" + +#include "msgq.h" +#include "event.h" + +EOSMsgQ _eos_event_q; +static EOSMsgItem event_q_array[EOS_EVT_SIZE_Q]; + +static eos_evt_handler_t evt_handler[EOS_EVT_MAX_EVT + 1]; + +static void evtq_handler(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = (type & EOS_EVT_MASK) >> 4; + + if (idx && (idx <= EOS_EVT_MAX_EVT)) { + evt_handler[idx](type, buffer, len); + } else { + eos_evtq_bad_handler(type, buffer, len); + } +} + +void eos_evtq_init(void) { + int i; + + evt_handler[0] = evtq_handler; + for (i=0; i<EOS_EVT_MAX_EVT; i++) { + evt_handler[i + 1] = eos_evtq_bad_handler; + } + eos_msgq_init(&_eos_event_q, event_q_array, EOS_EVT_SIZE_Q); +} + +int eos_evtq_push(unsigned char type, unsigned char *buffer, uint16_t len) { + clear_csr(mstatus, MSTATUS_MIE); + int ret = eos_msgq_push(&_eos_event_q, type, buffer, len); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +int eos_evtq_push_isr(unsigned char type, unsigned char *buffer, uint16_t len) { + return eos_msgq_push(&_eos_event_q, type, buffer, len); +} + +void eos_evtq_pop(unsigned char *type, unsigned char **buffer, uint16_t *len) { + clear_csr(mstatus, MSTATUS_MIE); + eos_msgq_pop(&_eos_event_q, type, buffer, len); + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_evtq_pop_isr(unsigned char *type, unsigned char **buffer, uint16_t *len) { + eos_msgq_pop(&_eos_event_q, type, buffer, len); +} + +void eos_evtq_wait(unsigned char type, unsigned char *selector, uint16_t sel_len, unsigned char **buffer, uint16_t *len) { + int rv = 0; + + while(!rv) { + clear_csr(mstatus, MSTATUS_MIE); + rv = eos_msgq_get(&_eos_event_q, type, selector, sel_len, buffer, len); + if (!rv) { + unsigned char _type; + unsigned char *_buffer; + uint16_t _len; + + eos_msgq_pop(&_eos_event_q, &_type, &_buffer, &_len); + if (_type) { + set_csr(mstatus, MSTATUS_MIE); + evt_handler[0](_type, _buffer, _len); + } else { + asm volatile ("wfi"); + set_csr(mstatus, MSTATUS_MIE); + } + } else { + set_csr(mstatus, MSTATUS_MIE); + } + } +} + +void eos_evtq_flush(void) { + clear_csr(mstatus, MSTATUS_MIE); + eos_evtq_flush_isr(); + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_evtq_flush_isr(void) { + unsigned char type; + unsigned char *buffer; + uint16_t len; + + do { + eos_msgq_pop(&_eos_event_q, &type, &buffer, &len); + if (type) { + set_csr(mstatus, MSTATUS_MIE); + evt_handler[0](type, buffer, len); + clear_csr(mstatus, MSTATUS_MIE); + } + } while (type); +} + +void eos_evtq_loop(void) { + unsigned char type; + unsigned char *buffer; + uint16_t len; + int foo = 1; + + while(foo) { + clear_csr(mstatus, MSTATUS_MIE); + eos_msgq_pop(&_eos_event_q, &type, &buffer, &len); + if (type) { + set_csr(mstatus, MSTATUS_MIE); + evt_handler[0](type, buffer, len); + } else { + asm volatile ("wfi"); + set_csr(mstatus, MSTATUS_MIE); + } + } +} + +void eos_evtq_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len) { + printf("evt bad handler:0x%x\n", type); +} + +void eos_evtq_set_handler(unsigned char type, eos_evt_handler_t handler) { + unsigned char idx = (type & EOS_EVT_MASK) >> 4; + + if (idx <= EOS_EVT_MAX_EVT) evt_handler[idx] = handler; +} + +eos_evt_handler_t eos_evtq_get_handler(unsigned char type) { + unsigned char idx = (type & EOS_EVT_MASK) >> 4; + + if (idx <= EOS_EVT_MAX_EVT) return evt_handler[idx]; + return NULL; +} diff --git a/fw/fe310/eos/event.h b/fw/fe310/eos/event.h new file mode 100644 index 0000000..ba906bb --- /dev/null +++ b/fw/fe310/eos/event.h @@ -0,0 +1,20 @@ +#include <stdint.h> + +#include "evt_def.h" + +typedef void (*eos_evt_handler_t) (unsigned char, unsigned char *, uint16_t); + +void eos_evtq_init(void); +int eos_evtq_push(unsigned char type, unsigned char *buffer, uint16_t len); +int eos_evtq_push_isr(unsigned char type, unsigned char *buffer, uint16_t len); +void eos_evtq_pop(unsigned char *type, unsigned char **buffer, uint16_t *len); +void eos_evtq_pop_isr(unsigned char *type, unsigned char **buffer, uint16_t *len); +void eos_evtq_wait(unsigned char type, unsigned char *selector, uint16_t sel_len, unsigned char **buffer, uint16_t *len); +void eos_evtq_flush(void); +void eos_evtq_flush_isr(void); +void eos_evtq_loop(void); + +void eos_evtq_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len); +void eos_evtq_set_handler(unsigned char type, eos_evt_handler_t handler); +eos_evt_handler_t eos_evtq_get_handler(unsigned char type); + diff --git a/fw/fe310/eos/evt_def.h b/fw/fe310/eos/evt_def.h new file mode 100644 index 0000000..16c4255 --- /dev/null +++ b/fw/fe310/eos/evt_def.h @@ -0,0 +1,12 @@ +#define EOS_EVT_TIMER 0x10 +#define EOS_EVT_I2S 0x20 +#define EOS_EVT_NET 0x30 +#define EOS_EVT_SPI 0x40 +#define EOS_EVT_UART 0x50 +#define EOS_EVT_UI 0x60 +#define EOS_EVT_USER 0x80 + +#define EOS_EVT_MAX_EVT 8 +#define EOS_EVT_MASK 0xF0 + +#define EOS_EVT_SIZE_Q 4 diff --git a/fw/fe310/eos/i2s.c b/fw/fe310/eos/i2s.c new file mode 100644 index 0000000..c8216ff --- /dev/null +++ b/fw/fe310/eos/i2s.c @@ -0,0 +1,407 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" +#include "prci_driver.h" + +#include "eos.h" +#include "interrupt.h" +#include "event.h" + +#include "i2s.h" +#include "i2s_def.h" +#include "irq_def.h" + +#define I2S_PWM_REG_CK PWM0_REG +#define I2S_PWM_REG_WS_MIC PWM1_REG +#define I2S_PWM_REG_WS_SPK PWM2_REG + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +#define EOS_ABUF_IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1)) + +EOSABuf _eos_i2s_mic_buf; +EOSABuf _eos_i2s_spk_buf; +uint32_t _eos_i2s_fmt = 0; +uint32_t _eos_i2s_mic_wm = 0; +uint32_t _eos_i2s_spk_wm = 0; +uint32_t _eos_i2s_mic_evt_enable = 0; +uint32_t _eos_i2s_spk_evt_enable = 0; + +static eos_i2s_handler_t i2s_spk_handler = NULL; +static eos_i2s_handler_t i2s_mic_handler = NULL; +static uint32_t i2s_clk_period; +static uint8_t i2s_mic_volume = 0; /* 0 - 8 */ +static uint8_t i2s_spk_volume = 16; /* 0 - 16 */ + +static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) { + buf->idx_r = 0; + buf->idx_w = 0; + buf->size = size; + buf->array = array; +} + +static int _abuf_push8(EOSABuf *buf, uint8_t sample) { + if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL; + + buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample; + buf->idx_w++; + return EOS_OK; +} + +static int _abuf_push16(EOSABuf *buf, uint16_t sample) { + if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL; + + buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample >> 8; + buf->array[EOS_ABUF_IDX_MASK(buf->idx_w + 1, buf->size)] = sample & 0xFF; + buf->idx_w += 2; + return EOS_OK; +} + +static int _abuf_pop8(EOSABuf *buf, uint8_t *sample) { + if (buf->idx_r == buf->idx_w) { + return EOS_ERR_EMPTY; + } else { + *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)]; + buf->idx_r++; + return EOS_OK; + } +} + +static int _abuf_pop16(EOSABuf *buf, uint16_t *sample) { + if (buf->idx_r == buf->idx_w) { + return EOS_ERR_EMPTY; + } else { + *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)] << 8; + *sample |= buf->array[EOS_ABUF_IDX_MASK(buf->idx_r + 1, buf->size)]; + buf->idx_r += 2; + return EOS_OK; + } +} + + +static void _abuf_flush(EOSABuf *buf) { + buf->idx_r = 0; + buf->idx_w = 0; +} + +static uint16_t _abuf_len(EOSABuf *buf) { + return buf->idx_w - buf->idx_r; +} + +static void i2s_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + switch(type & ~EOS_EVT_MASK) { + case EOS_I2S_ETYPE_MIC: + if (i2s_mic_handler) i2s_mic_handler(type); + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_mic_evt_enable = 1; + set_csr(mstatus, MSTATUS_MIE); + break; + case EOS_I2S_ETYPE_SPK: + if (i2s_spk_handler) i2s_spk_handler(type); + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_spk_evt_enable = 1; + set_csr(mstatus, MSTATUS_MIE); + break; + default: + eos_evtq_bad_handler(type, buffer, len); + break; + } +} + +static void _mic_vol_set(uint8_t vol) { + I2S_PWM_REG_WS_MIC(PWM_CMP2) = i2s_clk_period * (vol + 1); + I2S_PWM_REG_WS_MIC(PWM_CMP3) = I2S_PWM_REG_WS_MIC(PWM_CMP2) + i2s_clk_period * 16; +} + +static void _spk_vol_set(uint8_t vol) { + int spk_cmp = vol + i2s_mic_volume - 16; + + if (spk_cmp <= 0) { + I2S_PWM_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * (32 + spk_cmp); + I2S_PWM_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (64 + spk_cmp); + I2S_PWM_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * 33; + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK); + } else { + I2S_PWM_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_cmp; + I2S_PWM_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_cmp); + I2S_PWM_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (33 + spk_cmp); + GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << I2S_PIN_WS_SPK); + } +} + +extern void _eos_i2s_start_pwm(void); + +void eos_i2s_init(void) { + eos_evtq_set_handler(EOS_EVT_I2S, i2s_handle_evt); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_CK); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_CK); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_CK_SW); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_MIC); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SR); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SR); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_CK_SR); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_CK_SR); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_IN); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_IN); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_SD_IN); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_SD_IN); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_SD_OUT); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_SD_OUT); + + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SR) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK)); +} + +void eos_i2s_start(uint32_t sample_rate, unsigned char fmt) { + i2s_clk_period = ((PRCI_get_cpu_freq() / (sample_rate * 64)) & ~I2S_PWM_SCALE_CK_MASK) + 1; + + I2S_PWM_REG_CK(PWM_CMP0) = i2s_clk_period >> I2S_PWM_SCALE_CK; + I2S_PWM_REG_CK(PWM_CMP1) = I2S_PWM_REG_CK(PWM_CMP0) / 2; + I2S_PWM_REG_CK(PWM_CMP2) = 0; + I2S_PWM_REG_CK(PWM_CMP3) = 0; + + I2S_PWM_REG_WS_MIC(PWM_CMP0) = i2s_clk_period * 64 - 1; + I2S_PWM_REG_WS_MIC(PWM_CMP1) = i2s_clk_period * 32; + _mic_vol_set(i2s_mic_volume); + + I2S_PWM_REG_WS_SPK(PWM_CMP0) = i2s_clk_period * 64 - 1; + _spk_vol_set(i2s_spk_volume); + + I2S_PWM_REG_CK(PWM_COUNT) = 0; + I2S_PWM_REG_WS_MIC(PWM_COUNT) = 0; + I2S_PWM_REG_WS_SPK(PWM_COUNT) = i2s_clk_period / 2; + + _eos_i2s_fmt = fmt; + _eos_i2s_mic_evt_enable = 1; + _eos_i2s_spk_evt_enable = 1; + + eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS); + eos_intr_set_priority(I2S_IRQ_SD_ID, 0); + eos_intr_enable(I2S_IRQ_WS_ID); + eos_intr_enable(I2S_IRQ_SD_ID); + + _eos_i2s_start_pwm(); + /* + I2S_PWM_REG_CK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK; + I2S_PWM_REG_WS_MIC(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG; + I2S_PWM_REG_WS_SPK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG; + */ + + GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD_IN); + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SR); + + GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_CK); + GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_CK); + + GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_CK_SW); + + GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_WS_MIC); + + GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_WS_SPK); +} + +void eos_i2s_stop(void) { + I2S_PWM_REG_CK(PWM_CFG) = 0; + I2S_PWM_REG_WS_MIC(PWM_CFG) = 0; + I2S_PWM_REG_WS_SPK(PWM_CFG) = 0; + I2S_PWM_REG_CK(PWM_COUNT) = 0; + I2S_PWM_REG_WS_MIC(PWM_COUNT) = 0; + I2S_PWM_REG_WS_SPK(PWM_COUNT) = 0; + + _eos_i2s_mic_evt_enable = 0; + _eos_i2s_spk_evt_enable = 0; + eos_intr_set_priority(I2S_IRQ_WS_ID, 0); + eos_intr_set_priority(I2S_IRQ_SD_ID, 0); + eos_intr_disable(I2S_IRQ_WS_ID); + eos_intr_disable(I2S_IRQ_SD_ID); + + GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_CK); + GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_CK); + + GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_CK_SW); + + GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_WS_MIC); + + GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_WS_SPK); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_IN); + + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SR) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK)); +} + +void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) { + clear_csr(mstatus, MSTATUS_MIE); + _abuf_init(&_eos_i2s_mic_buf, mic_arr, mic_arr_size); + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler) { + clear_csr(mstatus, MSTATUS_MIE); + i2s_mic_handler = wm_handler; + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_i2s_mic_set_wm(uint16_t wm) { + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_mic_wm = wm; + set_csr(mstatus, MSTATUS_MIE); + +} + +uint16_t eos_i2s_mic_len(void) { + clear_csr(mstatus, MSTATUS_MIE); + uint16_t ret = _abuf_len(&_eos_i2s_mic_buf); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) { + uint16_t i; + uint16_t _ssize = 0; + + clear_csr(mstatus, MSTATUS_MIE); + _ssize = MIN(ssize, _abuf_len(&_eos_i2s_mic_buf)); + set_csr(mstatus, MSTATUS_MIE); + + for (i=0; i<_ssize; i++) { + sample[i] = _eos_i2s_mic_buf.array[EOS_ABUF_IDX_MASK(_eos_i2s_mic_buf.idx_r + i, _eos_i2s_mic_buf.size)]; + } + + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_mic_buf.idx_r += _ssize; + set_csr(mstatus, MSTATUS_MIE); + + return _ssize; +} + +int eos_i2s_mic_pop8(uint8_t *sample) { + clear_csr(mstatus, MSTATUS_MIE); + int ret = _abuf_pop8(&_eos_i2s_mic_buf, sample); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +int eos_i2s_mic_pop16(uint16_t *sample) { + clear_csr(mstatus, MSTATUS_MIE); + int ret = _abuf_pop16(&_eos_i2s_mic_buf, sample); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +int eos_i2s_mic_vol_get(void) { + return i2s_mic_volume; +} + +void eos_i2s_mic_vol_set(int vol) { + if ((vol < 0) || (vol > 8)) return; + + i2s_mic_volume = vol; + + clear_csr(mstatus, MSTATUS_MIE); + _mic_vol_set(vol); + _spk_vol_set(i2s_spk_volume); + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_i2s_spk_init(uint8_t *spk_arr, uint16_t spk_arr_size) { + clear_csr(mstatus, MSTATUS_MIE); + _abuf_init(&_eos_i2s_spk_buf, spk_arr, spk_arr_size); + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler) { + clear_csr(mstatus, MSTATUS_MIE); + i2s_spk_handler = wm_handler; + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_i2s_spk_set_wm(uint16_t wm) { + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_spk_wm = wm; + set_csr(mstatus, MSTATUS_MIE); +} + +uint16_t eos_i2s_spk_len(void) { + clear_csr(mstatus, MSTATUS_MIE); + uint16_t ret = _abuf_len(&_eos_i2s_spk_buf); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) { + uint16_t i; + uint16_t _ssize = 0; + + clear_csr(mstatus, MSTATUS_MIE); + _ssize = MIN(ssize, _eos_i2s_spk_buf.size - _abuf_len(&_eos_i2s_spk_buf)); + set_csr(mstatus, MSTATUS_MIE); + + for (i=0; i<_ssize; i++) { + _eos_i2s_spk_buf.array[EOS_ABUF_IDX_MASK(_eos_i2s_spk_buf.idx_w + i, _eos_i2s_spk_buf.size)] = sample[i]; + } + + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_spk_buf.idx_w += _ssize; + set_csr(mstatus, MSTATUS_MIE); + + return _ssize; +} + +int eos_i2s_spk_push8(uint8_t sample) { + clear_csr(mstatus, MSTATUS_MIE); + int ret = _abuf_push8(&_eos_i2s_spk_buf, sample); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +int eos_i2s_spk_push16(uint16_t sample) { + clear_csr(mstatus, MSTATUS_MIE); + int ret = _abuf_push16(&_eos_i2s_spk_buf, sample); + set_csr(mstatus, MSTATUS_MIE); + return ret; +} + +int eos_i2s_spk_vol_get(void) { + return i2s_spk_volume; +} + +void eos_i2s_spk_vol_set(int vol) { + if ((vol < 0) || (vol > 16)) return; + + i2s_spk_volume = vol; + + clear_csr(mstatus, MSTATUS_MIE); + _spk_vol_set(vol); + set_csr(mstatus, MSTATUS_MIE); +} diff --git a/fw/fe310/eos/i2s.h b/fw/fe310/eos/i2s.h new file mode 100644 index 0000000..744958e --- /dev/null +++ b/fw/fe310/eos/i2s.h @@ -0,0 +1,40 @@ +#include <stdint.h> + +#define EOS_I2S_FMT_ALAW 0 +#define EOS_I2S_FMT_PCM16 1 + +/* should match i2s_def.h definitions */ +#define EOS_I2S_ETYPE_MIC 1 +#define EOS_I2S_ETYPE_SPK 2 + + +typedef struct EOSABuf { + uint16_t idx_r; + uint16_t idx_w; + uint16_t size; + uint8_t *array; +} EOSABuf; + +typedef void (*eos_i2s_handler_t) (unsigned char); + +void eos_i2s_init(void); +void eos_i2s_start(uint32_t sample_rate, unsigned char fmt); +void eos_i2s_stop(void); +void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size); +void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler); +void eos_i2s_mic_set_wm(uint16_t wm); +uint16_t eos_i2s_mic_len(void); +uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize); +int eos_i2s_mic_pop8(uint8_t *sample); +int eos_i2s_mic_pop16(uint16_t *sample); +int eos_i2s_mic_vol_get(void); +void eos_i2s_mic_vol_set(int vol); +void eos_i2s_spk_init(uint8_t *mic_arr, uint16_t mic_arr_size); +void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler); +void eos_i2s_spk_set_wm(uint16_t wm); +uint16_t eos_i2s_spk_len(void); +uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize); +int eos_i2s_spk_push8(uint8_t sample); +int eos_i2s_spk_push16(uint16_t sample); +int eos_i2s_spk_vol_get(void); +void eos_i2s_spk_vol_set(int vol); diff --git a/fw/fe310/eos/i2s_def.h b/fw/fe310/eos/i2s_def.h new file mode 100644 index 0000000..3a09982 --- /dev/null +++ b/fw/fe310/eos/i2s_def.h @@ -0,0 +1,24 @@ +#define I2S_ETYPE_MIC 1 +#define I2S_ETYPE_SPK 2 + +#define I2S_PIN_CK 1 /* PWM 0.1 */ +#define I2S_PIN_CK_SW 21 /* PWM 1.2 */ +#define I2S_PIN_CK_SR 18 +#define I2S_PIN_WS_MIC 19 /* PWM 1.1 */ +#define I2S_PIN_WS_SPK 11 /* PWM 2.1 */ +#define I2S_PIN_SD_IN 13 +#define I2S_PIN_SD_OUT 12 + +#define I2S_IRQ_WS_ID (INT_PWM2_BASE + 0) +#define I2S_IRQ_SD_ID (INT_PWM2_BASE + 3) + +#define I2S_IDLE_CYCLES 8 + +#define I2S_PWM_SCALE_CK 2 +#define I2S_PWM_SCALE_CK_MASK 0x0003 + +/* asm */ +#define I2S_ABUF_OFF_IDXR 0 +#define I2S_ABUF_OFF_IDXW 2 +#define I2S_ABUF_OFF_SIZE 4 +#define I2S_ABUF_OFF_ARRAY 8 diff --git a/fw/fe310/eos/interrupt.c b/fw/fe310/eos/interrupt.c new file mode 100644 index 0000000..820d1fa --- /dev/null +++ b/fw/fe310/eos/interrupt.c @@ -0,0 +1,72 @@ +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <stdio.h> + +#include "encoding.h" +#include "platform.h" +#include "plic_driver.h" + +#include "interrupt.h" + +// Global Instance data for the PLIC +// for use by the PLIC Driver. +static plic_instance_t plic; + +static eos_intr_handler_t ext_interrupt_handler[PLIC_NUM_INTERRUPTS]; + +uintptr_t eos_intr_handle(uintptr_t int_num) { + if ((int_num >=1) && (int_num <= PLIC_NUM_INTERRUPTS) && (ext_interrupt_handler[int_num-1])) { + ext_interrupt_handler[int_num-1](); + } else { + printf("error:%d\n", int_num); + exit(int_num); + } + return int_num; +} + +void eos_intr_init(void) { + for (int i = 0; i < PLIC_NUM_INTERRUPTS; i++){ + ext_interrupt_handler[i] = NULL; + } + + /************************************************************************** + * Set up the PLIC + **************************************************************************/ + PLIC_init(&plic, + PLIC_CTRL_ADDR, + PLIC_NUM_INTERRUPTS, + PLIC_NUM_PRIORITIES); + + // Enable Global (PLIC) interrupts. + set_csr(mie, MIP_MEIP); + + // Enable all interrupts + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler) { + ext_interrupt_handler[int_num-1] = handler; + PLIC_set_priority(&plic, int_num, priority); + PLIC_enable_interrupt(&plic, int_num); +} + +void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler) { + ext_interrupt_handler[int_num-1] = handler; +} + +void eos_intr_set_priority(uint8_t int_num, uint8_t priority) { + PLIC_set_priority(&plic, int_num, priority); +} + +void eos_intr_enable(uint8_t int_num) { + PLIC_enable_interrupt(&plic, int_num); +} + +void eos_intr_disable(uint8_t int_num) { + PLIC_disable_interrupt(&plic, int_num); +} + +void eos_intr_mask(uint8_t priority) { + PLIC_set_threshold(&plic, priority); +} diff --git a/fw/fe310/eos/interrupt.h b/fw/fe310/eos/interrupt.h new file mode 100644 index 0000000..075e7eb --- /dev/null +++ b/fw/fe310/eos/interrupt.h @@ -0,0 +1,11 @@ +#include <stdint.h> + +typedef void (*eos_intr_handler_t) (void); + +void eos_intr_init(void); +void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler); +void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler); +void eos_intr_set_priority(uint8_t int_num, uint8_t priority); +void eos_intr_enable(uint8_t int_num); +void eos_intr_disable(uint8_t int_num); +void eos_intr_mask(uint8_t priority);
\ No newline at end of file diff --git a/fw/fe310/eos/irq_def.h b/fw/fe310/eos/irq_def.h new file mode 100644 index 0000000..5d9fb1e --- /dev/null +++ b/fw/fe310/eos/irq_def.h @@ -0,0 +1,11 @@ +#define IRQ_PRIORITY_I2S_SD 7 +#define IRQ_PRIORITY_I2S_WS 6 + +#define IRQ_PRIORITY_SPI_XCHG 5 + +#define IRQ_PRIORITY_NET_CTS 4 +#define IRQ_PRIORITY_NET_RTS 4 + +#define IRQ_PRIORITY_UART 1 + +#define IRQ_PRIORITY_UI 5 diff --git a/fw/fe310/eos/msgq.c b/fw/fe310/eos/msgq.c new file mode 100644 index 0000000..e76090c --- /dev/null +++ b/fw/fe310/eos/msgq.c @@ -0,0 +1,108 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "eos.h" +#include "msgq.h" + +#define IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1)) +#define IDX_HALF ((uint8_t)1 << (sizeof(uint8_t) * 8 - 1)) +#define IDX_LT(a,b) ((uint8_t)((uint8_t)(a) - (uint8_t)(b)) > IDX_HALF) +#define IDX_LTE(a,b) ((uint8_t)((uint8_t)(b) - (uint8_t)(a)) < IDX_HALF) + +void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size) { + msgq->idx_r = 0; + msgq->idx_w = 0; + msgq->size = size; + msgq->array = array; +} + +int eos_msgq_push(EOSMsgQ *msgq, unsigned char type, unsigned char *buffer, uint16_t len) { + if ((uint8_t)(msgq->idx_w - msgq->idx_r) == msgq->size) return EOS_ERR_FULL; + + uint8_t idx = IDX_MASK(msgq->idx_w, msgq->size); + msgq->array[idx].type = type; + msgq->array[idx].buffer = buffer; + msgq->array[idx].len = len; + msgq->idx_w++; + return EOS_OK; +} + +void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *type, unsigned char **buffer, uint16_t *len) { + if (msgq->idx_r == msgq->idx_w) { + *type = 0; + *buffer = NULL; + *len = 0; + } else { + uint8_t idx = IDX_MASK(msgq->idx_r, msgq->size); + *type = msgq->array[idx].type; + *buffer = msgq->array[idx].buffer; + *len = msgq->array[idx].len; + msgq->idx_r++; + } +} + +int eos_msgq_get(EOSMsgQ *msgq, unsigned char type, unsigned char *selector, uint16_t sel_len, unsigned char **buffer, uint16_t *len) { + uint8_t i, j, idx; + + if (msgq->idx_r == msgq->idx_w) { + *buffer = NULL; + *len = 0; + return 0; + } + + idx = IDX_MASK(msgq->idx_r, msgq->size); + if (type == msgq->array[idx].type) { + *buffer = msgq->array[idx].buffer; + *len = msgq->array[idx].len; + if ((selector == NULL) || (sel_len == 0) || ((sel_len <= *len) && (memcmp(selector, *buffer, sel_len) == 0))) { + msgq->idx_r++; + return 1; + } + } + for (i = msgq->idx_r + 1; IDX_LT(i, msgq->idx_w); i++) { + idx = IDX_MASK(i, msgq->size); + if (type== msgq->array[idx].type) { + *buffer = msgq->array[idx].buffer; + *len = msgq->array[idx].len; + if ((selector == NULL) || (sel_len == 0) || ((sel_len <= *len) && (memcmp(selector, *buffer, sel_len) == 0))) { + for (j = i + 1; IDX_LT(j, msgq->idx_w); j++) { + msgq->array[IDX_MASK(j - 1, msgq->size)] = msgq->array[IDX_MASK(j, msgq->size)]; + } + msgq->idx_w--; + return 1; + } + } + } + *buffer = NULL; + *len = 0; + return 0; +} + +uint8_t eos_msgq_len(EOSMsgQ *msgq) { + return (uint8_t)(msgq->idx_w - msgq->idx_r); +} + +void eos_bufq_init(EOSBufQ *bufq, unsigned char **array, uint8_t size) { + bufq->idx_r = 0; + bufq->idx_w = 0; + bufq->size = size; + bufq->array = array; +} + +int eos_bufq_push(EOSBufQ *bufq, unsigned char *buffer) { + if ((uint8_t)(bufq->idx_w - bufq->idx_r) == bufq->size) return EOS_ERR_FULL; + + bufq->array[IDX_MASK(bufq->idx_w++, bufq->size)] = buffer; + return EOS_OK; +} + +unsigned char *eos_bufq_pop(EOSBufQ *bufq) { + if (bufq->idx_r == bufq->idx_w) return NULL; + + return bufq->array[IDX_MASK(bufq->idx_r++, bufq->size)]; +} + +uint8_t eos_bufq_len(EOSBufQ *bufq) { + return (uint8_t)(bufq->idx_w - bufq->idx_r); +} diff --git a/fw/fe310/eos/msgq.h b/fw/fe310/eos/msgq.h new file mode 100644 index 0000000..9f2ca81 --- /dev/null +++ b/fw/fe310/eos/msgq.h @@ -0,0 +1,32 @@ +#include <stdint.h> + +typedef struct EOSMsgItem { + unsigned char type; + unsigned char *buffer; + uint16_t len; +} EOSMsgItem; + +typedef struct EOSMsgQ { + uint8_t idx_r; + uint8_t idx_w; + uint8_t size; + EOSMsgItem *array; +} EOSMsgQ; + +void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size); +int eos_msgq_push(EOSMsgQ *msgq, unsigned char type, unsigned char *buffer, uint16_t len); +void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *type, unsigned char **buffer, uint16_t *len); +int eos_msgq_get(EOSMsgQ *msgq, unsigned char type, unsigned char *selector, uint16_t sel_len, unsigned char **buffer, uint16_t *len); +uint8_t eos_msgq_len(EOSMsgQ *msgq); + +typedef struct EOSBufQ { + uint8_t idx_r; + uint8_t idx_w; + uint8_t size; + unsigned char **array; +} EOSBufQ; + +void eos_bufq_init(EOSBufQ *bufq, unsigned char **array, uint8_t size); +int eos_bufq_push(EOSBufQ *bufq, unsigned char *buffer); +unsigned char *eos_bufq_pop(EOSBufQ *bufq); +uint8_t eos_bufq_len(EOSBufQ *bufq); diff --git a/fw/fe310/eos/msgq_def.h b/fw/fe310/eos/msgq_def.h new file mode 100644 index 0000000..2ad5fc5 --- /dev/null +++ b/fw/fe310/eos/msgq_def.h @@ -0,0 +1,10 @@ +/* asm */ +#define MSGQ_OFF_IDXR 0 +#define MSGQ_OFF_IDXW 1 +#define MSGQ_OFF_SIZE 2 +#define MSGQ_OFF_ARRAY 4 + +#define MSGQ_ITEM_OFF_TYPE 0 +#define MSGQ_ITEM_OFF_BUF 4 +#define MSGQ_ITEM_OFF_SIZE 8 +#define MSGQ_ITEM_SIZE 12 diff --git a/fw/fe310/eos/net.c b/fw/fe310/eos/net.c new file mode 100644 index 0000000..297e8f0 --- /dev/null +++ b/fw/fe310/eos/net.c @@ -0,0 +1,496 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" + +#include "eos.h" +#include "msgq.h" +#include "event.h" +#include "interrupt.h" +#include "timer.h" +#include "power.h" + +#include "spi.h" +#include "spi_def.h" + +#include "net.h" +#include "net_def.h" +#include "irq_def.h" + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +static EOSBufQ net_buf_q; +static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ]; +static unsigned char net_bufq_buffer[EOS_NET_SIZE_BUFQ][EOS_NET_SIZE_BUF]; + +static EOSMsgQ net_send_q; +static EOSMsgItem net_sndq_array[EOS_NET_SIZE_BUFQ]; + +static volatile uint8_t net_state_flags = 0; +static unsigned char net_state_type = 0; +static uint32_t net_state_len_tx = 0; +static uint32_t net_state_len_rx = 0; +unsigned char *net_state_buf = NULL; + +static uint8_t net_state_next_cnt = 0; +static unsigned char *net_state_next_buf = NULL; + +static eos_evt_handler_t net_handler[EOS_NET_MAX_MTYPE]; +static uint16_t net_wrapper_acq[EOS_EVT_MAX_EVT]; +static uint16_t net_flags_acq[EOS_EVT_MAX_EVT]; + +static int net_xchg_sleep(void) { + int i; + int rv = EOS_OK; + volatile uint32_t x = 0; + + net_state_flags &= ~NET_STATE_FLAG_CTS; + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + + SPI1_REG(SPI_REG_TXFIFO) = 0xff; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + if (x & 0xFF) rv = EOS_ERR_BUSY; + + for (i=0; i<7; i++) { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = 0; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + } + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; + + return rv; +} + +static void net_xchg_wake(void) { + int i; + volatile uint32_t x = 0; + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + + for (i=0; i<8; i++) { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = 0; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + } + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; +} + +static void net_xchg_reset(void) { + net_state_flags &= ~NET_STATE_FLAG_CTS; + net_state_flags |= (NET_STATE_FLAG_RST | NET_STATE_FLAG_XCHG); + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + SPI1_REG(SPI_REG_TXFIFO) = 0; + SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(0); + SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM; +} + +static void net_xchg_start(unsigned char type, unsigned char *buffer, uint16_t len) { + net_state_flags &= ~NET_STATE_FLAG_CTS; + net_state_flags |= (NET_STATE_FLAG_INIT | NET_STATE_FLAG_XCHG); + + if (net_state_next_cnt && (net_state_next_buf == NULL)) type |= EOS_NET_MTYPE_FLAG_ONEW; + if (type & EOS_NET_MTYPE_FLAG_ONEW) net_state_flags |= NET_STATE_FLAG_ONEW; + + net_state_type = type; + net_state_len_tx = len; + net_state_len_rx = 0; + net_state_buf = buffer; + + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + SPI1_REG(SPI_REG_TXFIFO) = type; + SPI1_REG(SPI_REG_TXFIFO) = (len >> 8) & 0xFF; + SPI1_REG(SPI_REG_TXFIFO) = (len & 0xFF); + SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(2); + SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM; +} + +static int net_xchg_next(unsigned char *_buffer) { + unsigned char type; + unsigned char *buffer = NULL; + uint16_t len; + + eos_msgq_pop(&net_send_q, &type, &buffer, &len); + if (type) { + net_xchg_start(type, buffer, len); + } else if (net_state_flags & NET_STATE_FLAG_RTS) { + if (_buffer == NULL) _buffer = eos_bufq_pop(&net_buf_q); + if (_buffer) { + net_xchg_start(0, _buffer, 0); + return 0; + } + } + return 1; +} + +static void net_handle_xchg(void) { + volatile uint32_t r1, r2, r3; + uint32_t len; + + if (net_state_flags & NET_STATE_FLAG_RST) { + net_state_flags &= ~(NET_STATE_FLAG_RST | NET_STATE_FLAG_XCHG); + + r1 = SPI1_REG(SPI_REG_RXFIFO); + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; + SPI1_REG(SPI_REG_IE) = 0x0; + + return; + } else if (net_state_flags & NET_STATE_FLAG_INIT) { + net_state_flags &= ~NET_STATE_FLAG_INIT; + + r1 = SPI1_REG(SPI_REG_RXFIFO); + r2 = SPI1_REG(SPI_REG_RXFIFO); + r3 = SPI1_REG(SPI_REG_RXFIFO); + + if (net_state_flags & NET_STATE_FLAG_ONEW) { + r1 = 0; + r2 = 0; + r3 = 0; + } + + net_state_type = (r1 & 0xFF); + net_state_len_rx = (r2 & 0xFF) << 8; + net_state_len_rx |= (r3 & 0xFF); + len = MAX(net_state_len_tx, net_state_len_rx); + + // esp32 bug workaraund + if (len < 5) { + len = 5; + } else if ((len + 3) % 4 != 0) { + len = ((len + 3)/4 + 1) * 4 - 3; + } + + if (len > EOS_NET_SIZE_BUF) { + net_state_flags &= ~NET_STATE_FLAG_XCHG; + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; + SPI1_REG(SPI_REG_IE) = 0x0; + return; + } + + _eos_spi_xchg_init(net_state_buf, len, 0); + SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM); + SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM; + return; + } + + eos_spi_handle_xchg(); + if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_AUTO) { // exchange done + if (net_state_type) { + int r = eos_evtq_push_isr(EOS_EVT_NET | net_state_type, net_state_buf, net_state_len_rx); + if (r) eos_bufq_push(&net_buf_q, net_state_buf); + } else if (((net_state_flags & NET_STATE_FLAG_ONEW) || net_state_next_cnt) && (net_state_next_buf == NULL)) { + net_state_next_buf = net_state_buf; + net_state_flags &= ~NET_STATE_FLAG_ONEW; + } else { + eos_bufq_push(&net_buf_q, net_state_buf); + } + net_state_flags &= ~NET_STATE_FLAG_XCHG; + } +} + +static void net_handle_cts(void) { + GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS); + net_state_flags |= NET_STATE_FLAG_CTS; + + if (net_state_flags & NET_STATE_FLAG_RUN) { + net_xchg_next(NULL); + } +} + +static void net_handle_rts(void) { + uint32_t rts_offset = (1 << NET_PIN_RTS); + if (GPIO_REG(GPIO_RISE_IP) & rts_offset) { + GPIO_REG(GPIO_RISE_IP) = rts_offset; + net_state_flags |= NET_STATE_FLAG_RTS; + if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) net_xchg_reset(); + } else if (GPIO_REG(GPIO_FALL_IP) & rts_offset) { + GPIO_REG(GPIO_FALL_IP) = rts_offset; + net_state_flags &= ~NET_STATE_FLAG_RTS; + } +} + +static void net_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = (type & ~EOS_EVT_MASK) - 1; + + if (idx < EOS_NET_MAX_MTYPE) { + net_handler[idx](type, buffer, len); + } else { + eos_net_bad_handler(type, buffer, len); + } +} + +static int net_acquire(unsigned char reserved) { + int ret = 0; + + if (reserved) { + while (!ret) { + clear_csr(mstatus, MSTATUS_MIE); + if (net_state_next_buf) { + ret = 1; + net_state_next_cnt--; + } else { + asm volatile ("wfi"); + } + set_csr(mstatus, MSTATUS_MIE); + } + } else { + clear_csr(mstatus, MSTATUS_MIE); + if (net_state_next_buf == NULL) net_state_next_buf = eos_bufq_pop(&net_buf_q); + ret = (net_state_next_buf != NULL); + if (!ret) net_state_next_cnt++; + set_csr(mstatus, MSTATUS_MIE); + } + return ret; +} + +static void evt_handler_wrapper(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char idx, uint16_t flag) { + int ok; + + ok = net_acquire(net_wrapper_acq[idx] & flag); + if (ok) { + eos_evtq_get_handler(type)(type, buffer, len); + eos_net_release(); + net_wrapper_acq[idx] &= ~flag; + } else { + net_wrapper_acq[idx] |= flag; + eos_evtq_push(type, buffer, len); + } +} + +static void evt_handler(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = ((type & EOS_EVT_MASK) >> 4) - 1; + uint16_t flag = (uint16_t)1 << ((type & ~EOS_EVT_MASK) - 1); + + if (idx < EOS_EVT_MAX_EVT) { + if (flag & net_flags_acq[idx]) { + evt_handler_wrapper(type, buffer, len, idx, flag); + } else { + eos_evtq_get_handler(type)(type, buffer, len); + } + } else { + eos_evtq_bad_handler(type, buffer, len); + } +} + +void eos_net_init(void) { + int i; + + eos_msgq_init(&net_send_q, net_sndq_array, EOS_NET_SIZE_BUFQ); + eos_bufq_init(&net_buf_q, net_bufq_array, EOS_NET_SIZE_BUFQ); + for (i=0; i<EOS_NET_SIZE_BUFQ; i++) { + eos_bufq_push(&net_buf_q, net_bufq_buffer[i]); + } + + for (i=0; i<EOS_NET_MAX_MTYPE; i++) { + net_handler[i] = eos_net_bad_handler; + } + eos_evtq_set_handler(0, evt_handler); + eos_evtq_set_handler(EOS_EVT_NET, net_handle_evt); + + GPIO_REG(GPIO_INPUT_EN) |= (1 << NET_PIN_CTS); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << NET_PIN_CTS); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << NET_PIN_CTS); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << NET_PIN_CTS); + + GPIO_REG(GPIO_RISE_IE) |= (1 << NET_PIN_CTS); + eos_intr_set(INT_GPIO_BASE + NET_PIN_CTS, IRQ_PRIORITY_NET_CTS, net_handle_cts); + + GPIO_REG(GPIO_INPUT_EN) |= (1 << NET_PIN_RTS); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << NET_PIN_RTS); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << NET_PIN_RTS); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << NET_PIN_RTS); + + GPIO_REG(GPIO_RISE_IE) |= (1 << NET_PIN_RTS); + GPIO_REG(GPIO_FALL_IE) |= (1 << NET_PIN_RTS); + eos_intr_set(INT_GPIO_BASE + NET_PIN_RTS, IRQ_PRIORITY_NET_RTS, net_handle_rts); +} + +void eos_net_start(void) { + eos_intr_set_handler(INT_SPI1_BASE, net_handle_xchg); + SPI1_REG(SPI_REG_SCKDIV) = NET_SPI_DIV; + SPI1_REG(SPI_REG_CSID) = NET_SPI_CSID; + + clear_csr(mstatus, MSTATUS_MIE); + net_state_flags |= NET_STATE_FLAG_RUN; + if (net_state_flags & NET_STATE_FLAG_CTS) { + net_xchg_next(NULL); + } + set_csr(mstatus, MSTATUS_MIE); +} + +void eos_net_stop(void) { + uint8_t done = 0; + + clear_csr(mstatus, MSTATUS_MIE); + if (net_state_flags & NET_STATE_FLAG_RUN) { + net_state_flags &= ~NET_STATE_FLAG_RUN; + done = !(net_state_flags & NET_STATE_FLAG_XCHG); + } else { + done = 1; + } + set_csr(mstatus, MSTATUS_MIE); + + while (!done) { + clear_csr(mstatus, MSTATUS_MIE); + done = !(net_state_flags & NET_STATE_FLAG_XCHG); + if (!done) asm volatile ("wfi"); + set_csr(mstatus, MSTATUS_MIE); + } +} + +int eos_net_sleep(uint32_t timeout) { + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t then_ms = timeout + *mtime * 1000 / EOS_TIMER_RTC_FREQ; + uint8_t done = 0; + int rv = EOS_OK; + + clear_csr(mstatus, MSTATUS_MIE); + if (!(net_state_flags & NET_STATE_FLAG_RUN)) rv = EOS_ERR; + set_csr(mstatus, MSTATUS_MIE); + + if (rv) return rv; + + do { + if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) return EOS_ERR_TIMEOUT; + clear_csr(mstatus, MSTATUS_MIE); + eos_evtq_flush_isr(); + done = (eos_msgq_len(&net_send_q) == 0); + done = done && (!(net_state_flags & NET_STATE_FLAG_RTS) && (net_state_flags & NET_STATE_FLAG_CTS)); + if (done) done = (net_xchg_sleep() == EOS_OK); + if (!done) { + asm volatile ("wfi"); + set_csr(mstatus, MSTATUS_MIE); + } + } while (!done); + + while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) { + if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) { + rv = EOS_ERR_TIMEOUT; + break; + } + asm volatile ("wfi"); + } + + if (!rv) { + GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS); + net_state_flags &= ~NET_STATE_FLAG_RUN; + } + + set_csr(mstatus, MSTATUS_MIE); + + return rv; +} + +int eos_net_wake(uint8_t source) { + int rv = EOS_OK; + + clear_csr(mstatus, MSTATUS_MIE); + if (net_state_flags & NET_STATE_FLAG_RUN) rv = EOS_ERR; + set_csr(mstatus, MSTATUS_MIE); + + if (rv) return rv; + + eos_intr_set_handler(INT_SPI1_BASE, net_handle_xchg); + SPI1_REG(SPI_REG_SCKDIV) = NET_SPI_DIV; + SPI1_REG(SPI_REG_CSID) = NET_SPI_CSID; + + clear_csr(mstatus, MSTATUS_MIE); + net_state_flags |= NET_STATE_FLAG_RUN; + if (source) { + if (source != EOS_PWR_WAKE_BTN) { + net_xchg_wake(); + } + if (!(net_state_flags & NET_STATE_FLAG_CTS)) { + while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) { + asm volatile ("wfi"); + } + GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS); + } + net_xchg_reset(); + if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_RTS)) net_state_flags |= NET_STATE_FLAG_RTS; + } + set_csr(mstatus, MSTATUS_MIE); + + return rv; +} + +void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len) { + eos_evtq_bad_handler(type, buffer, len); + if (buffer) eos_net_free(buffer, 0); +} + +void eos_net_set_handler(unsigned char mtype, eos_evt_handler_t handler) { + if (handler == NULL) handler = eos_net_bad_handler; + if (mtype && (mtype <= EOS_NET_MAX_MTYPE)) net_handler[mtype - 1] = handler; +} + +void eos_net_acquire_for_evt(unsigned char type, char acq) { + unsigned char idx = ((type & EOS_EVT_MASK) >> 4) - 1; + uint16_t flag = type & ~EOS_EVT_MASK ? (uint16_t)1 << ((type & ~EOS_EVT_MASK) - 1) : 0xFFFF; + + if (idx < EOS_EVT_MAX_EVT) { + net_flags_acq[idx] &= ~flag; + if (acq) net_flags_acq[idx] |= flag; + } +} + +void eos_net_acquire(void) { + unsigned char acq = net_acquire(0); + if (!acq) net_acquire(1); +} + +void eos_net_release(void) { + clear_csr(mstatus, MSTATUS_MIE); + if (!net_state_next_cnt && net_state_next_buf) { + eos_bufq_push(&net_buf_q, net_state_next_buf); + net_state_next_buf = NULL; + } + set_csr(mstatus, MSTATUS_MIE); +} + +unsigned char *eos_net_alloc(void) { + unsigned char *ret = NULL; + + clear_csr(mstatus, MSTATUS_MIE); + ret = net_state_next_buf; + net_state_next_buf = NULL; + set_csr(mstatus, MSTATUS_MIE); + + return ret; +} + +void eos_net_free(unsigned char *buffer, unsigned char more) { + uint8_t do_release = 1; + + clear_csr(mstatus, MSTATUS_MIE); + if ((more || net_state_next_cnt) && (net_state_next_buf == NULL)) { + net_state_next_buf = buffer; + } else { + if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) do_release = net_xchg_next(buffer); + if (do_release) eos_bufq_push(&net_buf_q, buffer); + } + set_csr(mstatus, MSTATUS_MIE); +} + +int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more) { + int rv = EOS_OK; + + if (more) { + type |= EOS_NET_MTYPE_FLAG_ONEW; + } + clear_csr(mstatus, MSTATUS_MIE); + if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) { + net_xchg_start(type, buffer, len); + } else { + rv = eos_msgq_push(&net_send_q, type, buffer, len); + if (rv) eos_bufq_push(&net_buf_q, buffer); + } + set_csr(mstatus, MSTATUS_MIE); + + return rv; +} diff --git a/fw/fe310/eos/net.h b/fw/fe310/eos/net.h new file mode 100644 index 0000000..1aaea1f --- /dev/null +++ b/fw/fe310/eos/net.h @@ -0,0 +1,36 @@ +#include <stdint.h> +#include "event.h" + +/* common */ +#define EOS_NET_SIZE_BUF 1500 + +#define EOS_NET_MTYPE_SOCK 1 +#define EOS_NET_MTYPE_POWER 4 + +#define EOS_NET_MTYPE_WIFI 5 +#define EOS_NET_MTYPE_CELL 6 +#define EOS_NET_MTYPE_SIP 7 +#define EOS_NET_MTYPE_APP 8 + +#define EOS_NET_MAX_MTYPE 8 + +#define EOS_NET_MTYPE_FLAG_ONEW 0x80 + +/* fe310 specific */ +#define EOS_NET_SIZE_BUFQ 2 + +void eos_net_init(void); +void eos_net_start(void); +void eos_net_stop(void); +int eos_net_sleep(uint32_t timeout); +int eos_net_wake(uint8_t source); + +void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len); +void eos_net_set_handler(unsigned char type, eos_evt_handler_t handler); +void eos_net_acquire_for_evt(unsigned char type, char acq); + +void eos_net_acquire(void); +void eos_net_release(void); +unsigned char *eos_net_alloc(void); +void eos_net_free(unsigned char *buffer, unsigned char more); +int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more); diff --git a/fw/fe310/eos/net_def.h b/fw/fe310/eos/net_def.h new file mode 100644 index 0000000..9aa25dd --- /dev/null +++ b/fw/fe310/eos/net_def.h @@ -0,0 +1,13 @@ +#define NET_PIN_RTS 20 +#define NET_PIN_CTS 22 + +#define NET_STATE_FLAG_RUN 0x01 +#define NET_STATE_FLAG_RST 0x02 +#define NET_STATE_FLAG_RTS 0x04 +#define NET_STATE_FLAG_CTS 0x08 +#define NET_STATE_FLAG_INIT 0x10 +#define NET_STATE_FLAG_ONEW 0x20 +#define NET_STATE_FLAG_XCHG 0x40 + +#define NET_SPI_DIV 16 +#define NET_SPI_CSID 3 diff --git a/fw/fe310/eos/power.c b/fw/fe310/eos/power.c new file mode 100644 index 0000000..5c874e0 --- /dev/null +++ b/fw/fe310/eos/power.c @@ -0,0 +1,111 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" + +#include "eos.h" +#include "event.h" +#include "timer.h" +#include "net.h" +#include "eve/eve.h" + +#include "power.h" + +#define PWR_RTC_SCALE 15 +#define PWR_RTC_SFREQ (EOS_TIMER_RTC_FREQ >> PWR_RTC_SCALE) + +static eos_evt_handler_t evt_handler[EOS_PWR_MAX_MTYPE]; +static unsigned char power_btn_down; + +static void power_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + if ((buffer == NULL) || (len < 1)) { + eos_net_bad_handler(type, buffer, len); + return; + } + + unsigned char mtype = buffer[0]; + if (mtype < EOS_PWR_MAX_MTYPE) { + evt_handler[mtype](type, buffer, len); + } else { + eos_net_bad_handler(type, buffer, len); + } +} + +static void power_handle_btn(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char level = buffer[1]; + + eos_net_free(buffer, 0); + if (!level) { + power_btn_down = 1; + return; + } + if (!power_btn_down) return; + + eos_power_sleep(); +} + +void eos_power_init(void) { + int i; + + for (i=0; i<EOS_PWR_MAX_MTYPE; i++) { + evt_handler[i] = eos_net_bad_handler; + } + eos_net_set_handler(EOS_NET_MTYPE_POWER, power_handle_evt); + eos_power_set_handler(EOS_PWR_MTYPE_BUTTON, power_handle_btn); + + AON_REG(AON_PMUKEY) = 0x51F15E; + AON_REG(AON_PMUIE) = 0x5; + + AON_REG(AON_RTCCMP) = 0xFFFFFFFF; + AON_REG(AON_RTCCFG) = PWR_RTC_SCALE; + AON_REG(AON_RTCHI) = 0; + AON_REG(AON_RTCLO) = 0; +} + +uint8_t eos_power_wakeup_cause(void) { + return AON_REG(AON_PMUCAUSE) & 0xff; +} + +uint8_t eos_power_reset_cause(void) { + return (AON_REG(AON_PMUCAUSE) >> 8) & 0xff; +} + +void eos_power_sleep(void) { + eos_spi_dev_start(EOS_DEV_DISP); + eve_sleep(); + eos_spi_dev_stop(); + eos_net_sleep(1000); + + AON_REG(AON_PMUKEY) = 0x51F15E; + AON_REG(AON_PMUSLEEP) = 1; +} + +void eos_power_wake_at(uint32_t msec) { + uint32_t pmuie; + + AON_REG(AON_RTCCFG) |= AON_RTCCFG_ENALWAYS; + AON_REG(AON_RTCCMP) = msec * PWR_RTC_SFREQ / 1000; + + pmuie = AON_REG(AON_PMUIE) | 0x2; + AON_REG(AON_PMUKEY) = 0x51F15E; + AON_REG(AON_PMUIE) = pmuie; +} + +void eos_power_wake_disable(void) { + uint32_t pmuie; + + AON_REG(AON_RTCCMP) = 0xFFFFFFFF; + AON_REG(AON_RTCCFG) &= ~AON_RTCCFG_ENALWAYS; + AON_REG(AON_RTCHI) = 0; + AON_REG(AON_RTCLO) = 0; + + pmuie = AON_REG(AON_PMUIE) & ~0x2; + AON_REG(AON_PMUKEY) = 0x51F15E; + AON_REG(AON_PMUIE) = pmuie; +} + +void eos_power_set_handler(unsigned char mtype, eos_evt_handler_t handler) { + if (handler == NULL) handler = eos_net_bad_handler; + if (mtype < EOS_PWR_MAX_MTYPE) evt_handler[mtype] = handler; +} diff --git a/fw/fe310/eos/power.h b/fw/fe310/eos/power.h new file mode 100644 index 0000000..466573f --- /dev/null +++ b/fw/fe310/eos/power.h @@ -0,0 +1,22 @@ +#include <stdint.h> +#include "event.h" + +#define EOS_PWR_MTYPE_BUTTON 0 + +#define EOS_PWR_MAX_MTYPE 2 + +#define EOS_PWR_WAKE_RST 0 +#define EOS_PWR_WAKE_RTC 1 +#define EOS_PWR_WAKE_BTN 2 + +#define EOS_PWR_RST_PWRON 0 +#define EOS_PWR_RST_EXT 1 +#define EOS_PWR_RST_WDOG 2 + +void eos_power_init(void); +uint8_t eos_power_wakeup_cause(void); +uint8_t eos_power_reset_cause(void); +void eos_power_sleep(void); +void eos_power_wake_at(uint32_t msec); +void eos_power_wake_disable(void); +void eos_power_set_handler(unsigned char mtype, eos_evt_handler_t handler);
\ No newline at end of file diff --git a/fw/fe310/eos/sock.c b/fw/fe310/eos/sock.c new file mode 100644 index 0000000..720e620 --- /dev/null +++ b/fw/fe310/eos/sock.c @@ -0,0 +1,96 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "eos.h" +#include "event.h" +#include "net.h" + +#include "sock.h" + +static eos_evt_handler_t evt_handler[EOS_SOCK_MAX_SOCK]; + +static void sock_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char sock; + if ((buffer == NULL) || (len < 2)) { + eos_net_bad_handler(type, buffer, len); + return; + } + + sock = buffer[1]; + if ((sock == 0) || (sock > EOS_SOCK_MAX_SOCK)) { + eos_net_bad_handler(type, buffer, len); + return; + } + + sock--; + switch(buffer[0]) { + case EOS_SOCK_MTYPE_PKT: + evt_handler[sock](type, buffer, len); + break; + default: + eos_net_bad_handler(type, buffer, len); + break; + } +} + +void eos_sock_init(void) { + int i; + + for (i=0; i<EOS_SOCK_MAX_SOCK; i++) { + evt_handler[i] = eos_net_bad_handler; + } + eos_net_set_handler(EOS_NET_MTYPE_SOCK, sock_handle_evt); +} + +void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler) { + if (handler == NULL) handler = eos_net_bad_handler; + if (sock && (sock <= EOS_SOCK_MAX_SOCK)) evt_handler[sock - 1] = handler; +} + +int eos_sock_open_udp(void) { + unsigned char type = EOS_SOCK_MTYPE_OPEN_DGRAM; + unsigned char *buffer = eos_net_alloc(); + uint16_t buf_size; + int rv, sock; + + buffer[0] = type; + rv = eos_net_send(EOS_NET_MTYPE_SOCK, buffer, 1, 0); + if (rv) return rv; + + eos_evtq_wait(EOS_NET_MTYPE_SOCK, &type, 1, &buffer, &buf_size); + if (buf_size < 2) { + eos_net_free(buffer, 0); + return EOS_ERR_NET; + } + + sock = buffer[1]; + eos_net_free(buffer, 1); + + if (sock == 0) return EOS_ERR_NET; + return sock; +} + +void eos_sock_close(unsigned char sock) { + unsigned char *buffer = eos_net_alloc(); + buffer[0] = EOS_SOCK_MTYPE_CLOSE; + buffer[1] = sock; + eos_net_send(EOS_NET_MTYPE_SOCK, buffer, 2, 1); +} + +int eos_sock_sendto(unsigned char sock, unsigned char *buffer, uint16_t size, unsigned char more, EOSNetAddr *addr) { + unsigned char type = EOS_NET_MTYPE_SOCK; + + buffer[0] = EOS_SOCK_MTYPE_PKT; + buffer[1] = sock; + memcpy(buffer+2, addr->host, sizeof(addr->host)); + memcpy(buffer+2+sizeof(addr->host), &addr->port, sizeof(addr->port)); + return eos_net_send(type, buffer, size, more); +} + +void eos_sock_getfrom(unsigned char *buffer, EOSNetAddr *addr) { + memcpy(addr->host, buffer+2, sizeof(addr->host)); + memcpy(&addr->port, buffer+2+sizeof(addr->host), sizeof(addr->port)); +} + + diff --git a/fw/fe310/eos/sock.h b/fw/fe310/eos/sock.h new file mode 100644 index 0000000..d647381 --- /dev/null +++ b/fw/fe310/eos/sock.h @@ -0,0 +1,25 @@ +#include <stdint.h> +#include "event.h" + +#define EOS_SOCK_MTYPE_PKT 0 +#define EOS_SOCK_MTYPE_OPEN_DGRAM 1 +#define EOS_SOCK_MTYPE_CLOSE 127 + +#define EOS_SOCK_MAX_SOCK 2 + +#define EOS_SOCK_SIZE_UDP_HDR 8 + +#define EOS_IPv4_ADDR_SIZE 4 + +typedef struct EOSNetAddr { + unsigned char host[EOS_IPv4_ADDR_SIZE]; + uint16_t port; +} EOSNetAddr; + +void eos_sock_init(void); +void eos_sock_set_handler(unsigned char sock, eos_evt_handler_t handler); + +int eos_sock_open_udp(void); +void eos_sock_close(unsigned char sock); +int eos_sock_sendto(unsigned char sock, unsigned char *buffer, uint16_t size, unsigned char more, EOSNetAddr *addr); +void eos_sock_getfrom(unsigned char *buffer, EOSNetAddr *addr); diff --git a/fw/fe310/eos/spi.c b/fw/fe310/eos/spi.c new file mode 100644 index 0000000..fb47313 --- /dev/null +++ b/fw/fe310/eos/spi.c @@ -0,0 +1,330 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" + +#include "eos.h" +#include "msgq.h" +#include "interrupt.h" +#include "event.h" + +#include "net.h" +#include "spi.h" +#include "spi_def.h" +#include "irq_def.h" + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) +#define SPI_IOF_MASK (((uint32_t)1 << IOF_SPI1_SCK) | ((uint32_t)1 << IOF_SPI1_MOSI) | ((uint32_t)1 << IOF_SPI1_MISO)) | ((uint32_t)1 << IOF_SPI1_SS0) | ((uint32_t)1 << IOF_SPI1_SS2) | ((uint32_t)1 << IOF_SPI1_SS3) + +static uint8_t spi_dev; +static uint8_t spi_dev_cs_pin; +static volatile uint8_t spi_state_flags; +static unsigned char spi_in_xchg; + +static uint32_t spi_state_len = 0; +static uint32_t spi_state_idx_tx = 0; +static uint32_t spi_state_idx_rx = 0; +static unsigned char *spi_state_buf = NULL; + +static eos_evt_handler_t evt_handler[EOS_SPI_MAX_DEV]; + +static void spi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = (type & ~EOS_EVT_MASK) - 1; + if (idx < EOS_SPI_MAX_DEV) { + evt_handler[idx](type, buffer, len); + } else { + eos_evtq_bad_handler(type, buffer, len); + } +} + +void eos_spi_init(void) { + int i; + + for (i=0; i<EOS_SPI_MAX_DEV; i++) { + evt_handler[i] = eos_evtq_bad_handler; + } + eos_evtq_set_handler(EOS_EVT_SPI, spi_handle_evt); + eos_intr_set(INT_SPI1_BASE, IRQ_PRIORITY_SPI_XCHG, NULL); + + SPI1_REG(SPI_REG_SCKMODE) = SPI_MODE0; + SPI1_REG(SPI_REG_FMT) = SPI_FMT_PROTO(SPI_PROTO_S) | + SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) | + SPI_FMT_DIR(SPI_DIR_RX) | + SPI_FMT_LEN(8); + + GPIO_REG(GPIO_IOF_SEL) &= ~SPI_IOF_MASK; + GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK; + + // There is no way here to change the CS polarity. + // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF; +} + +void eos_spi_start(unsigned char dev, uint32_t div, uint32_t csid, uint8_t pin) { + spi_dev = dev; + spi_state_flags = 0; + SPI1_REG(SPI_REG_SCKDIV) = div; + SPI1_REG(SPI_REG_CSID) = csid; + if (csid != SPI_CSID_NONE) { + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; + } else { + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF; + spi_dev_cs_pin = pin; + } + eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg); +} + +void eos_spi_stop(void) { + eos_spi_flush(); + spi_dev = 0; +} + +void eos_spi_set_handler(unsigned char dev, eos_evt_handler_t handler) { + if (handler == NULL) handler = eos_evtq_bad_handler; + if (dev && (dev <= EOS_SPI_MAX_DEV)) evt_handler[dev - 1] = handler; +} + +void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags) { + spi_state_flags &= 0xF0; + spi_state_flags |= (SPI_FLAG_XCHG | flags); + spi_state_buf = buffer; + spi_state_len = len; + spi_state_idx_tx = 0; + spi_state_idx_rx = 0; +} + +static void spi_xchg_finish(void) { + uint8_t done = 0; + + while (!done) { + clear_csr(mstatus, MSTATUS_MIE); + done = !(spi_state_flags & SPI_FLAG_XCHG); + if (!done) asm volatile ("wfi"); + set_csr(mstatus, MSTATUS_MIE); + } + spi_in_xchg = 0; +} + +void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags) { + if (spi_in_xchg) spi_xchg_finish(); + + spi_in_xchg=1; + _eos_spi_xchg_init(buffer, len, flags); + + eos_spi_cs_set(); + SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM); + SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM; +} + +void eos_spi_handle_xchg(void) { + int i; + uint16_t sz_chunk = MIN(spi_state_len - spi_state_idx_tx, SPI_SIZE_CHUNK); + + for (i=0; i<sz_chunk; i++) { + volatile uint32_t x = SPI1_REG(SPI_REG_TXFIFO); + if (x & SPI_TXFIFO_FULL) break; + SPI1_REG(SPI_REG_TXFIFO) = spi_state_buf[spi_state_idx_tx+i]; + } + spi_state_idx_tx += i; + + for (i=0; i<spi_state_idx_tx - spi_state_idx_rx; i++) { + volatile uint32_t x = SPI1_REG(SPI_REG_RXFIFO); + if (x & SPI_RXFIFO_EMPTY) break; + spi_state_buf[spi_state_idx_rx+i] = x & 0xFF; + } + spi_state_idx_rx += i; + + if (spi_state_idx_tx == spi_state_len) { + if ((spi_state_idx_rx == spi_state_len) || (spi_state_flags & EOS_SPI_FLAG_TX)) { + spi_state_flags &= ~SPI_FLAG_XCHG; + if (!(spi_state_flags & EOS_SPI_FLAG_MORE)) eos_spi_cs_clear(); + SPI1_REG(SPI_REG_IE) = 0x0; + if (spi_dev) eos_evtq_push_isr(EOS_EVT_SPI | spi_dev, spi_state_buf, spi_state_len); + } else { + SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(MIN(spi_state_len - spi_state_idx_rx - 1, SPI_SIZE_WM - 1)); + SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM; + } + } +} + +void eos_spi_cs_set(void) { + /* cs low */ + if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) { + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << spi_dev_cs_pin); + } else { + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; + } +} + +void eos_spi_cs_clear(void) { + /* cs high */ + if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) { + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_dev_cs_pin); + } else { + SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; + } +} + +uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags) { + volatile uint32_t x = 0; + uint8_t rx = !(flags & EOS_SPI_FLAG_TX); + + spi_state_flags &= 0xF0; + spi_state_flags |= flags; + + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = data; + + if (rx) { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + } + + return x & 0xFF; +} + +uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags) { + volatile uint32_t x = 0; + uint8_t rx = !(flags & EOS_SPI_FLAG_TX); + uint16_t r = 0; + + spi_state_flags &= 0xF0; + spi_state_flags |= flags; + + if (flags & EOS_SPI_FLAG_BSWAP) { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF); + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8; + } else { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF); + } + + if (rx) { + if (flags & EOS_SPI_FLAG_BSWAP) { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + } else { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + } + } + + return r; +} + +uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags) { + volatile uint32_t x = 0; + uint8_t rx = !(flags & EOS_SPI_FLAG_TX); + uint32_t r = 0; + + spi_state_flags &= 0xF0; + spi_state_flags |= flags; + + if (flags & EOS_SPI_FLAG_BSWAP) { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF); + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16; + } else { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF); + } + + if (rx) { + if (flags & EOS_SPI_FLAG_BSWAP) { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 16; + } else { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 16; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + } + } + + return r; +} + +uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags) { + volatile uint32_t x = 0; + uint8_t rx = !(flags & EOS_SPI_FLAG_TX); + uint32_t r = 0; + + spi_state_flags &= 0xF0; + spi_state_flags |= flags; + + if (flags & EOS_SPI_FLAG_BSWAP) { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF); + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24; + } else { + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8; + while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); + SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF); + } + + if (rx) { + if (flags & EOS_SPI_FLAG_BSWAP) { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 16; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 24; + } else { + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 24; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 16; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF) << 8; + while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); + r |= (x & 0xFF); + } + } + + return r; +} + +void eos_spi_flush(void) { + volatile uint32_t x = 0; + + if (spi_in_xchg) spi_xchg_finish(); + + SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1); + while (!x) { + if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) x = SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY; + } +} diff --git a/fw/fe310/eos/spi.h b/fw/fe310/eos/spi.h new file mode 100644 index 0000000..b291ad3 --- /dev/null +++ b/fw/fe310/eos/spi.h @@ -0,0 +1,26 @@ +#include <stdint.h> +#include "event.h" +#include "spi_dev.h" + +#define EOS_SPI_MAX_DEV EOS_DEV_MAX_DEV + +#define EOS_SPI_FLAG_TX 0x01 +#define EOS_SPI_FLAG_MORE 0x02 +#define EOS_SPI_FLAG_BSWAP 0x04 + +void eos_spi_init(void); +void eos_spi_start(unsigned char dev, uint32_t div, uint32_t csid, uint8_t pin); +void eos_spi_stop(void); +void eos_spi_set_handler(unsigned char dev, eos_evt_handler_t handler); + +void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags); +void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags); +void eos_spi_handle_xchg(void); + +void eos_spi_cs_set(void); +void eos_spi_cs_clear(void); +uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags); +uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags); +uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags); +uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags); +void eos_spi_flush(void); diff --git a/fw/fe310/eos/spi_def.h b/fw/fe310/eos/spi_def.h new file mode 100644 index 0000000..06f7251 --- /dev/null +++ b/fw/fe310/eos/spi_def.h @@ -0,0 +1,12 @@ +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x01 +#define SPI_MODE2 0x02 +#define SPI_MODE3 0x03 + +/* DO NOT TOUCH THEESE */ +#define SPI_SIZE_CHUNK 4 +#define SPI_SIZE_WM 2 + +#define SPI_FLAG_XCHG 0x10 + +#define SPI_CSID_NONE 1
\ No newline at end of file diff --git a/fw/fe310/eos/spi_dev.c b/fw/fe310/eos/spi_dev.c new file mode 100644 index 0000000..aed26bc --- /dev/null +++ b/fw/fe310/eos/spi_dev.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" + +#include "spi.h" +#include "net.h" + +#include "spi_def.h" +#include "spi_dev.h" + + +#define SPI_DIV_DISP 16 +#define SPI_DIV_CARD 16 +#define SPI_DIV_CAM 16 + +#define SPI_CSID_DISP 2 +#define SPI_CSID_CARD 0 + +#define SPI_CSPIN_CAM 23 + +static uint16_t spi_dev_div[EOS_DEV_MAX_DEV]; + +void eos_spi_dev_start(unsigned char dev) { + eos_net_stop(); + switch (dev) { + case EOS_DEV_DISP: + eos_spi_start(dev, spi_dev_div[dev-1], SPI_CSID_DISP, 0); + break; + case EOS_DEV_CARD: + eos_spi_start(dev, spi_dev_div[dev-1], SPI_CSID_CARD, 0); + break; + case EOS_DEV_CAM: + eos_spi_start(dev, spi_dev_div[dev-1], SPI_CSID_NONE, SPI_CSPIN_CAM); + break; + } +} + +void eos_spi_dev_stop(void) { + eos_spi_stop(); + eos_net_start(); +} + +void eos_spi_dev_init(void) { + spi_dev_div[EOS_DEV_DISP - 1] = SPI_DIV_DISP; + spi_dev_div[EOS_DEV_CARD - 1] = SPI_DIV_CARD; + spi_dev_div[EOS_DEV_CAM - 1] = SPI_DIV_CAM; + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << SPI_CSPIN_CAM); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << SPI_CSPIN_CAM); + GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << SPI_CSPIN_CAM); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << SPI_CSPIN_CAM); + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << SPI_CSPIN_CAM); +} + +void eos_spi_dev_set_div(unsigned char dev, uint16_t div) { + spi_dev_div[dev-1] = div; +} diff --git a/fw/fe310/eos/spi_dev.h b/fw/fe310/eos/spi_dev.h new file mode 100644 index 0000000..21dcee9 --- /dev/null +++ b/fw/fe310/eos/spi_dev.h @@ -0,0 +1,11 @@ +#define EOS_DEV_DISP 1 +#define EOS_DEV_CARD 2 +#define EOS_DEV_CAM 3 + +#define EOS_DEV_MAX_DEV 3 + +void eos_spi_dev_init(void); +void eos_spi_dev_start(unsigned char dev); +void eos_spi_dev_stop(void); + +void eos_spi_dev_set_div(unsigned char dev, uint16_t div); diff --git a/fw/fe310/eos/timer.c b/fw/fe310/eos/timer.c new file mode 100644 index 0000000..e07b9a6 --- /dev/null +++ b/fw/fe310/eos/timer.c @@ -0,0 +1,131 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "encoding.h" +#include "platform.h" + +#include "msgq.h" +#include "event.h" +#include "timer.h" + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +static eos_timer_handler_t timer_handler[EOS_TIMER_MAX_ETYPE + 1]; +static uint64_t timer_next[EOS_TIMER_MAX_ETYPE + 1]; + +static void timer_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = (type & ~EOS_EVT_MASK); + + if (idx && (idx <= EOS_TIMER_MAX_ETYPE) && timer_handler[idx]) { + timer_handler[idx](type); + } else { + eos_evtq_bad_handler(type, buffer, len); + } +} + +void _eos_timer_handle(void) { + int i; + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + uint64_t now = *mtime; + uint64_t next = 0; + + for (i = 0; i <= EOS_TIMER_MAX_ETYPE; i++) { + if (timer_next[i] && (timer_next[i] <= now)) { + timer_next[i] = 0; + if (i == 0) { + timer_handler[0](0); + } else { + eos_evtq_push_isr(EOS_EVT_TIMER | i, NULL, 0); + } + } + next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]); + } + *mtimecmp = next; + if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP); +} + +void eos_timer_init(void) { + int i; + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + + clear_csr(mie, MIP_MTIP); + *mtimecmp = 0; + for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) { + timer_next[i] = 0; + timer_handler[i] = NULL; + } + eos_evtq_set_handler(EOS_EVT_TIMER, timer_handle_evt); +} + +void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler) { + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + + if (!evt && (*mtimecmp != 0)) clear_csr(mie, MIP_MTIP); + timer_handler[evt] = handler; + if (!evt && (*mtimecmp != 0)) set_csr(mie, MIP_MTIP); +} + +uint32_t eos_timer_get(unsigned char evt) { + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + uint64_t now; + uint32_t ret; + + if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP); + now = *mtime; + if (timer_next[evt]) { + ret = (timer_next[evt] > now) ? (timer_next[evt] - now) * 1000 / EOS_TIMER_RTC_FREQ : 0; + } else { + ret = EOS_TIMER_NONE; + } + if (*mtimecmp != 0) set_csr(mie, MIP_MTIP); + + return ret; +} + +void eos_timer_set(uint32_t msec, unsigned char evt) { + int i; + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + uint64_t tick = *mtime + msec * (uint64_t)EOS_TIMER_RTC_FREQ / 1000; + uint64_t next = 0; + + if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP); + timer_next[evt] = tick; + for (i = 0; i <= EOS_TIMER_MAX_ETYPE; i++) { + next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]); + } + *mtimecmp = next; + if (*mtimecmp != 0) set_csr(mie, MIP_MTIP); +} + +void eos_timer_clear(unsigned char evt) { + int i; + uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP); + uint64_t next = 0; + + if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP); + if (timer_next[evt]) { + timer_next[evt] = 0; + for (i = 0; i <= EOS_TIMER_MAX_ETYPE; i++) { + next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]); + } + *mtimecmp = next; + } + if (*mtimecmp != 0) set_csr(mie, MIP_MTIP); +} + + +void eos_time_sleep(uint32_t msec) { + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t now_ms = *mtime * 1000 / EOS_TIMER_RTC_FREQ; + + while (*mtime * 1000 / EOS_TIMER_RTC_FREQ < now_ms + msec); +} + +uint64_t eos_time_get_tick(void) { + volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); + return *mtime; +} diff --git a/fw/fe310/eos/timer.h b/fw/fe310/eos/timer.h new file mode 100644 index 0000000..2ac53f7 --- /dev/null +++ b/fw/fe310/eos/timer.h @@ -0,0 +1,22 @@ +#include <stdint.h> + +#define EOS_TIMER_ETYPE_UI 1 +#define EOS_TIMER_ETYPE_ECP 2 +#define EOS_TIMER_ETYPE_USER 4 + +#define EOS_TIMER_MAX_ETYPE 4 + +#define EOS_TIMER_NONE 0xffffffff +#define EOS_TIMER_RTC_FREQ 32768 + +typedef void (*eos_timer_handler_t) (unsigned char); + +void eos_timer_init(void); +void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler); + +uint32_t eos_timer_get(unsigned char evt); +void eos_timer_set(uint32_t msec, unsigned char evt); +void eos_timer_clear(unsigned char evt); + +void eos_time_sleep(uint32_t msec); +uint64_t eos_time_get_tick(void); diff --git a/fw/fe310/eos/trap_entry.S b/fw/fe310/eos/trap_entry.S new file mode 100644 index 0000000..c24236b --- /dev/null +++ b/fw/fe310/eos/trap_entry.S @@ -0,0 +1,531 @@ +#include "encoding.h" +#include "sifive/bits.h" + +#define MCAUSE_INT 0x80000000 +#define MCAUSE_EXT (MCAUSE_INT | IRQ_M_EXT) +#define MCAUSE_TIMER (MCAUSE_INT | IRQ_M_TIMER) + +#define PLIC_PRIORITY 0x0C000000 +#define PLIC_THRESHOLD 0x0C200000 +#define PLIC_CLAIM 0x0C200004 + +#define PWM0_CTRL_ADDR 0x10015000 +#define PWM1_CTRL_ADDR 0x10025000 +#define PWM2_CTRL_ADDR 0x10035000 +#include "sifive/devices/pwm.h" + +#define GPIO_CTRL_ADDR 0x10012000 +#include "sifive/devices/gpio.h" + +#define SPI0_CTRL_ADDR 0x10014000 +#define SPI1_CTRL_ADDR 0x10024000 +#include "sifive/devices/spi.h" + +#include "evt_def.h" +#include "msgq_def.h" +#include "i2s_def.h" + +#define INT_PWM0_BASE 40 +#define INT_PWM1_BASE 44 +#define INT_PWM2_BASE 48 + +#define I2S_PWM_CTRL_ADDR_CK PWM0_CTRL_ADDR +#define I2S_PWM_CTRL_ADDR_WS_MIC PWM1_CTRL_ADDR +#define I2S_PWM_CTRL_ADDR_WS_SPK PWM2_CTRL_ADDR + +#define IOF_SPI1_SS0 2 +#define IOF_SPI1_SS1 8 +#define IOF_SPI1_SS2 9 +#define IOF_SPI1_SS3 10 + +#define INT_SPI1_BASE 6 +#define INT_GPIO_BASE 8 + +#include "net_def.h" +#include "spi_def.h" +#include "irq_def.h" + + + .section .data.entry + .align 4 + +.global eos_trap_entry +eos_trap_entry: + addi sp, sp, -8*REGBYTES + STORE x8, 0*REGBYTES(sp) + STORE x9, 1*REGBYTES(sp) + STORE x18, 2*REGBYTES(sp) + STORE x19, 3*REGBYTES(sp) + STORE x20, 4*REGBYTES(sp) + STORE x21, 5*REGBYTES(sp) + STORE x22, 6*REGBYTES(sp) + STORE x23, 7*REGBYTES(sp) + + csrr x8, mcause + li x18, MCAUSE_EXT + bne x8, x18, handle_intr + li x18, PLIC_CLAIM + lw x9, 0(x18) + li x18, I2S_IRQ_WS_ID + beq x9, x18, i2s_handle_ws + li x18, I2S_IRQ_SD_ID + beq x9, x18, i2s_handle_sd + j handle_intr + +evtq_push: + la x9, _eos_event_q + lbu x18, MSGQ_OFF_IDXR(x9) + lbu x19, MSGQ_OFF_IDXW(x9) + lbu x20, MSGQ_OFF_SIZE(x9) + + sub x18, x19, x18 + andi x18, x18, 0xff + beq x18, x20, 0f + + addi x20, x20, -1 + and x20, x20, x19 + li x18, MSGQ_ITEM_SIZE + mul x20, x20, x18 + lw x21, MSGQ_OFF_ARRAY(x9) + add x21, x21, x20 + + addi x19, x19, 1 + sb x19, MSGQ_OFF_IDXW(x9) + jalr x0, x22 + +0: + mv x20, x0 + jalr x0, x21 + +i2s_handle_sd: + # exit if too early + li x18, I2S_PWM_CTRL_ADDR_WS_SPK + lw x8, PWM_COUNT(x18) + lw x9, PWM_CMP3(x18) + bltu x8, x9, i2s_handle_sd_exit + + # disable sd irq + li x18, PLIC_PRIORITY + sw x0, 4*I2S_IRQ_SD_ID(x18) + + la x9, _eos_i2s_fmt + lw x23, 0(x9) + +i2s_abuf_pop: + # pop from spk buf -> x8 + mv x8, x0 + la x9, _eos_i2s_spk_buf + lhu x18, I2S_ABUF_OFF_IDXR(x9) + lhu x19, I2S_ABUF_OFF_IDXW(x9) + lhu x20, I2S_ABUF_OFF_SIZE(x9) + + beq x18, x19, i2s_handle_sd_xchg + + addi x20, x20, -1 + and x20, x20, x18 + lw x21, I2S_ABUF_OFF_ARRAY(x9) + add x21, x21, x20 + bnez x23, 0f + lbu x8, 0(x21) + addi x18, x18, 1 + j 1f +0: + lb x8, 0(x21) + lbu x20, 1(x21) + slli x8, x8, 8 + or x8, x8, x20 + addi x18, x18, 2 +1: + sh x18, I2S_ABUF_OFF_IDXR(x9) + + li x21, 0xffff + sub x18, x19, x18 + and x18, x18, x21 + + # check for push to event queue + la x9, _eos_i2s_spk_wm + lw x20, 0(x9) + beqz x20, i2s_decode + bgtu x18, x20, i2s_decode + + la x9, _eos_i2s_spk_evt_enable + lw x18, 0(x9) + beqz x18, i2s_decode + sw x0, 0(x9) + + # push to event queue + jal x22, evtq_push + beqz x21, i2s_decode + li x18, (EOS_EVT_I2S | I2S_ETYPE_SPK) + sb x18, MSGQ_ITEM_OFF_TYPE(x21) + +i2s_decode: + bnez x23, i2s_handle_sd_xchg + # aLaw decode -> x8 + xori x8, x8, 0x55 + andi x9, x8, 0x80 + beqz x9, 0f + li x9, 1 + slli x9, x9, 7 + not x9, x9 + and x8, x8, x9 + li x9, -1 +0: + andi x18, x8, 0xf0 + srli x18, x18, 4 + addi x18, x18, 4 + + li x19, 4 + beq x18, x19, 1f + + andi x8, x8, 0x0f + addi x19, x18, -4 + sll x8, x8, x19 + + li x19, 1 + sll x19, x19, x18 + or x8, x8, x19 + + li x19, 1 + addi x18, x18, -5 + sll x19, x19, x18 + or x8, x8, x19 + j 2f +1: + slli x8, x8, 1 + ori x8, x8, 1 +2: + beqz x9, i2s_handle_sd_xchg + mul x8, x8, x9 + +i2s_handle_sd_xchg: + # read/write shift reg: x8 -> sr -> x8 + li x18, GPIO_CTRL_ADDR + li x19, (0x1 << I2S_PIN_SD_IN) + li x20, (0x1 << I2S_PIN_SD_OUT) + li x21, (0x1 << I2S_PIN_CK_SR) + lw x22, GPIO_OUTPUT_VAL(x18) + + lw x9, GPIO_OUTPUT_EN(x18) + or x9, x9, x20 + sw x9, GPIO_OUTPUT_EN(x18) + + not x20, x20 + xor x22, x22, x21 + + li x23, 16 +0: + # write bit + li x9, 1 + slli x9, x9, 15 + and x9, x8, x9 + slli x8, x8, 1 +#if I2S_PIN_SD_OUT > 15 + slli x9, x9, (I2S_PIN_SD_OUT - 15) +#else + srli x9, x9, (15 - I2S_PIN_SD_OUT) +#endif + and x22, x22, x20 + or x22, x22, x9 + + # read bit + lw x9, GPIO_INPUT_VAL(x18) + and x9, x9, x19 + srli x9, x9, I2S_PIN_SD_IN + or x8, x8, x9 + + # 74HC595 ck low (I2S_PIN_CK_SR high) + xor x22, x22, x21 + sw x22, GPIO_OUTPUT_VAL(x18) + + # idle + li x9, I2S_IDLE_CYCLES +1: + addi x9, x9, -1 + bnez x9, 1b + + # 74HC595 ck high (I2S_PIN_CK_SR low) + xor x22, x22, x21 + sw x22, GPIO_OUTPUT_VAL(x18) + + # idle + li x9, I2S_IDLE_CYCLES +1: + addi x9, x9, -1 + bnez x9, 1b + + addi x23, x23, -1 + beqz x23, 2f + j 0b + +2: + # 74HC595 ck low (I2S_PIN_CK_SR high) + xor x22, x22, x21 + sw x22, GPIO_OUTPUT_VAL(x18) + + lw x9, GPIO_OUTPUT_EN(x18) + and x9, x9, x20 + sw x9, GPIO_OUTPUT_EN(x18) + + slli x8, x8, 16 + srai x8, x8, 16 + + la x9, _eos_i2s_fmt + lw x23, 0(x9) + +i2s_encode: + bnez x23, i2s_abuf_push + # aLaw encode -> x8 + li x18, 0x800 + li x19, 7 + bgez x8, 0f + neg x8, x8 + lui x9, 0x80000 + or x8, x8, x9 +0: + and x9, x8, x18 + beq x9, x18, 1f + beqz x19, 1f + srli x18, x18, 1 + addi x19, x19, -1 + j 0b +1: + mv x9, x19 + bnez x9, 2f + addi x9, x9, 1 +2: + sra x8, x8, x9 + li x9, 0x8000000f + and x8, x8, x9 + slli x19, x19, 4 + or x8, x8, x19 + bgez x8, 3f + ori x8, x8, 0x80 +3: + xori x8, x8, 0x55 + andi x8, x8, 0xff + +i2s_abuf_push: + # push to mic buf + la x9, _eos_i2s_mic_buf + lhu x18, I2S_ABUF_OFF_IDXR(x9) + lhu x19, I2S_ABUF_OFF_IDXW(x9) + lhu x20, I2S_ABUF_OFF_SIZE(x9) + li x21, 0xffff + + sub x18, x19, x18 + and x18, x18, x21 + beq x18, x20, i2s_handle_sd_exit + + addi x20, x20, -1 + and x20, x20, x19 + lw x21, I2S_ABUF_OFF_ARRAY(x9) + add x21, x21, x20 + bnez x23, 0f + sb x8, 0(x21) + addi x19, x19, 1 + addi x18, x18, 1 + j 1f +0: + sb x8, 1(x21) + srli x8, x8, 8 + sb x8, 0(x21) + addi x19, x19, 2 + addi x18, x18, 2 +1: + sh x19, I2S_ABUF_OFF_IDXW(x9) + + # check for push to event queue + la x9, _eos_i2s_mic_wm + lw x20, 0(x9) + beqz x20, i2s_handle_sd_exit + bltu x18, x20, i2s_handle_sd_exit + + la x9, _eos_i2s_mic_evt_enable + lw x18, 0(x9) + beqz x18, i2s_handle_sd_exit + sw x0, 0(x9) + + # push to event queue + jal x22, evtq_push + beqz x21, i2s_handle_sd_exit + li x18, (EOS_EVT_I2S | I2S_ETYPE_MIC) + sb x18, MSGQ_ITEM_OFF_TYPE(x21) + +i2s_handle_sd_exit: + # complete + li x18, I2S_IRQ_SD_ID + li x19, PLIC_CLAIM + sw x18, 0(x19) + + # exit + j trap_exit_data + +i2s_handle_ws: + # enable sd irq + li x18, PLIC_PRIORITY + li x19, IRQ_PRIORITY_I2S_SD + sw x19, 4*I2S_IRQ_SD_ID(x18) + + # complete + li x18, I2S_IRQ_WS_ID + li x19, PLIC_CLAIM + sw x18, 0(x19) + + # exit + j trap_exit_data + +.global _eos_i2s_start_pwm +_eos_i2s_start_pwm: + addi sp, sp, -8*REGBYTES + STORE x8, 0*REGBYTES(sp) + STORE x9, 1*REGBYTES(sp) + STORE x18, 2*REGBYTES(sp) + STORE x19, 3*REGBYTES(sp) + STORE x20, 4*REGBYTES(sp) + STORE x21, 5*REGBYTES(sp) + STORE x22, 6*REGBYTES(sp) + STORE x23, 7*REGBYTES(sp) + + li x18, I2S_PWM_CTRL_ADDR_CK + li x19, I2S_PWM_CTRL_ADDR_WS_MIC + li x20, I2S_PWM_CTRL_ADDR_WS_SPK + li x21, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK + li x22, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG + li x23, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG + sw x21, PWM_CFG(x18) + sw x22, PWM_CFG(x19) + sw x23, PWM_CFG(x20) + + LOAD x8, 0*REGBYTES(sp) + LOAD x9, 1*REGBYTES(sp) + LOAD x18, 2*REGBYTES(sp) + LOAD x19, 3*REGBYTES(sp) + LOAD x20, 4*REGBYTES(sp) + LOAD x21, 5*REGBYTES(sp) + LOAD x22, 6*REGBYTES(sp) + LOAD x23, 7*REGBYTES(sp) + addi sp, sp, 8*REGBYTES + + ret + +.global _eos_flash_set +_eos_flash_set: + li a3, SPI0_CTRL_ADDR + sw x0, SPI_REG_FCTRL(a3) + sw a0, SPI_REG_SCKDIV(a3) + sw a1, SPI_REG_FFMT(a3) + li a0, 1 + sw a0, SPI_REG_FCTRL(a3) + ret + +trap_exit_data: + # Remain in M-mode after mret + li x18, MSTATUS_MPP + csrs mstatus, x18 + + LOAD x8, 0*REGBYTES(sp) + LOAD x9, 1*REGBYTES(sp) + LOAD x18, 2*REGBYTES(sp) + LOAD x19, 3*REGBYTES(sp) + LOAD x20, 4*REGBYTES(sp) + LOAD x21, 5*REGBYTES(sp) + LOAD x22, 6*REGBYTES(sp) + LOAD x23, 7*REGBYTES(sp) + addi sp, sp, 8*REGBYTES + + mret + +handle_intr: + lui x18, %hi(trap_entry_text) + addi x18, x18, %lo(trap_entry_text) + jalr x0, x18 + + .section .text.entry + .align 2 + +trap_entry_text: + addi sp, sp, -24*REGBYTES + + STORE x1, 0*REGBYTES(sp) + STORE x2, 1*REGBYTES(sp) + STORE x3, 2*REGBYTES(sp) + STORE x4, 3*REGBYTES(sp) + STORE x5, 4*REGBYTES(sp) + STORE x6, 5*REGBYTES(sp) + STORE x7, 6*REGBYTES(sp) + STORE x10, 7*REGBYTES(sp) + STORE x11, 8*REGBYTES(sp) + STORE x12, 9*REGBYTES(sp) + STORE x13, 10*REGBYTES(sp) + STORE x14, 11*REGBYTES(sp) + STORE x15, 12*REGBYTES(sp) + STORE x16, 13*REGBYTES(sp) + STORE x17, 14*REGBYTES(sp) + STORE x24, 15*REGBYTES(sp) + STORE x25, 16*REGBYTES(sp) + STORE x26, 17*REGBYTES(sp) + STORE x27, 18*REGBYTES(sp) + STORE x28, 19*REGBYTES(sp) + STORE x29, 20*REGBYTES(sp) + STORE x30, 21*REGBYTES(sp) + STORE x31, 22*REGBYTES(sp) + + li x18, MCAUSE_TIMER + beq x8, x18, handle_timer + li x18, MCAUSE_EXT + beq x8, x18, handle_ext + mv a0, x8 + call _exit + +handle_timer: + call _eos_timer_handle + j trap_exit_text + +handle_ext: + mv a0, x9 + call eos_intr_handle + li x18, PLIC_CLAIM + sw a0, 0(x18) + j trap_exit_text + +trap_exit_text: + # Remain in M-mode after mret + li t0, MSTATUS_MPP + csrs mstatus, t0 + + LOAD x1, 0*REGBYTES(sp) + LOAD x2, 1*REGBYTES(sp) + LOAD x3, 2*REGBYTES(sp) + LOAD x4, 3*REGBYTES(sp) + LOAD x5, 4*REGBYTES(sp) + LOAD x6, 5*REGBYTES(sp) + LOAD x7, 6*REGBYTES(sp) + LOAD x10, 7*REGBYTES(sp) + LOAD x11, 8*REGBYTES(sp) + LOAD x12, 9*REGBYTES(sp) + LOAD x13, 10*REGBYTES(sp) + LOAD x14, 11*REGBYTES(sp) + LOAD x15, 12*REGBYTES(sp) + LOAD x16, 13*REGBYTES(sp) + LOAD x17, 14*REGBYTES(sp) + LOAD x24, 15*REGBYTES(sp) + LOAD x25, 16*REGBYTES(sp) + LOAD x26, 17*REGBYTES(sp) + LOAD x27, 18*REGBYTES(sp) + LOAD x28, 19*REGBYTES(sp) + LOAD x29, 20*REGBYTES(sp) + LOAD x30, 21*REGBYTES(sp) + LOAD x31, 22*REGBYTES(sp) + + LOAD x8, 24*REGBYTES(sp) + LOAD x9, 25*REGBYTES(sp) + LOAD x18, 26*REGBYTES(sp) + LOAD x19, 27*REGBYTES(sp) + LOAD x20, 28*REGBYTES(sp) + LOAD x21, 29*REGBYTES(sp) + LOAD x22, 30*REGBYTES(sp) + LOAD x23, 31*REGBYTES(sp) + + addi sp, sp, 32*REGBYTES + mret diff --git a/fw/fe310/eos/uart.c b/fw/fe310/eos/uart.c new file mode 100644 index 0000000..e9349a7 --- /dev/null +++ b/fw/fe310/eos/uart.c @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "encoding.h" +#include "platform.h" + +#include "eos.h" +#include "interrupt.h" +#include "event.h" + +#include "uart.h" +#include "irq_def.h" + +static eos_uart_handler_t uart_handler[EOS_UART_MAX_ETYPE]; + +static void uart_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + unsigned char idx = (type & ~EOS_EVT_MASK) - 1; + + if ((idx < EOS_UART_MAX_ETYPE) && uart_handler[idx]) { + uart_handler[idx](type); + } else { + eos_evtq_bad_handler(type, buffer, len); + } +} + +static void uart_handle_intr(void) { + if (UART0_REG(UART_REG_IP) & UART_IP_TXWM) { + UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM; + eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_TX, NULL, 0); + } + if (UART0_REG(UART_REG_IP) & UART_IP_RXWM) { + UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM; + eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_RX, NULL, 0); + } +} + +void eos_uart_init(void) { + int i; + + for (i=0; i<EOS_UART_MAX_ETYPE; i++) { + uart_handler[i] = NULL; + } + eos_evtq_set_handler(EOS_EVT_UART, uart_handle_evt); + eos_intr_set(INT_UART0_BASE, IRQ_PRIORITY_UART, uart_handle_intr); +} + +void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler) { + if (type && (type <= EOS_UART_MAX_ETYPE)) uart_handler[type - 1] = handler; +} + +void eos_uart_txwm_set(uint8_t wm) { + UART0_REG(UART_REG_TXCTRL) &= ~UART_TXWM(0xFFFF); + UART0_REG(UART_REG_TXCTRL) |= UART_TXWM(wm); + UART0_REG(UART_REG_IE) |= UART_IP_TXWM; +} + +void eos_uart_txwm_clear(void) { + UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM; +} + +void eos_uart_rxwm_set(uint8_t wm) { + UART0_REG(UART_REG_RXCTRL) &= ~UART_RXWM(0xFFFF); + UART0_REG(UART_REG_RXCTRL) |= UART_RXWM(wm); + UART0_REG(UART_REG_IE) |= UART_IP_RXWM; +} + +void eos_uart_rxwm_clear(void) { + UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM; +} + +int eos_uart_putc(int c, char b) { + if (b) { + while (UART0_REG(UART_REG_TXFIFO) & 0x80000000); + UART0_REG(UART_REG_TXFIFO) = c & 0xff; + } else { + if (UART0_REG(UART_REG_TXFIFO) & 0x80000000) return EOS_ERR_FULL; + UART0_REG(UART_REG_TXFIFO) = c & 0xff; + } + return EOS_OK; +} + +int eos_uart_getc(char b) { + volatile uint32_t r; + + if (b) { + while ((r = UART0_REG(UART_REG_RXFIFO)) & 0x80000000); + } else { + r = UART0_REG(UART_REG_RXFIFO); + if (r & 0x80000000) return EOS_ERR_EMPTY; + } + return r & 0xff; +}
\ No newline at end of file diff --git a/fw/fe310/eos/uart.h b/fw/fe310/eos/uart.h new file mode 100644 index 0000000..da5faab --- /dev/null +++ b/fw/fe310/eos/uart.h @@ -0,0 +1,18 @@ +#include <stdint.h> + +#define EOS_UART_ETYPE_TX 1 +#define EOS_UART_ETYPE_RX 2 + +#define EOS_UART_MAX_ETYPE 2 + +typedef void (*eos_uart_handler_t) (unsigned char); + +void eos_uart_init(void); +void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler); + +void eos_uart_txwm_set(uint8_t wm); +void eos_uart_txwm_clear(void); +void eos_uart_rxwm_set(uint8_t wm); +void eos_uart_rxwm_clear(void); +int eos_uart_putc(int c, char b); +int eos_uart_getc(char b);
\ No newline at end of file diff --git a/fw/fe310/eos/unicode.c b/fw/fe310/eos/unicode.c new file mode 100644 index 0000000..2915791 --- /dev/null +++ b/fw/fe310/eos/unicode.c @@ -0,0 +1,180 @@ +#include "unicode.h" + +int utf8_enc(utf32_t ch, utf8_t *str) { + if (ch <= 0x7f) { + str[0] = ch; + return 1; + } else if (ch <= 0x7ff) { + str[0] = 0xc0 | (ch >> 6); + str[1] = 0x80 | (ch & 0x3f); + return 2; + } else if (ch <= 0xffff) { + if ((ch >= 0xd800) && (ch <= 0xdfff)) return UTF_ERR; + str[0] = 0xe0 | (ch >> 12); + str[1] = 0x80 | ((ch >> 6) & 0x3f); + str[2] = 0x80 | (ch & 0x3f); + return 3; + } else if (ch <= 0x10ffff) { + str[0] = 0xf0 | (ch >> 18); + str[1] = 0x80 | ((ch >> 12) & 0x3f); + str[2] = 0x80 | ((ch >> 6) & 0x3f); + str[3] = 0x80 | (ch & 0x3f); + return 4; + } else { + return UTF_ERR; + } +} + +int utf8_dec(utf8_t *str, utf32_t *ch) { + if ((str[0] & 0x80) == 0x00) { + *ch = str[0]; + return 1; + } else if ((str[0] & 0xe0) == 0xc0) { + if ((str[1] & 0xc0) != 0x80) return UTF_ERR; + *ch = (utf32_t)(str[0] & 0x1f) << 6; + *ch |= (utf32_t)(str[1] & 0x3f); + if (*ch < 0x80) return UTF_ERR; + return 2; + } else if ((str[0] & 0xf0) == 0xe0) { + if (((str[1] & 0xc0) != 0x80) || ((str[2] & 0xc0) != 0x80)) return UTF_ERR; + *ch = (utf32_t)(str[0] & 0x0f) << 12; + *ch |= (utf32_t)(str[1] & 0x3f) << 6; + *ch |= (utf32_t)(str[2] & 0x3f); + if ((*ch >= 0xd800) && (*ch <= 0xdfff)) return UTF_ERR; + if (*ch < 0x800) return UTF_ERR; + return 3; + } else if ((str[0] & 0xf8) == 0xf0) { + if (((str[1] & 0xc0) != 0x80) || ((str[2] & 0xc0) != 0x80) || ((str[3] & 0xc0) != 0x80)) return UTF_ERR; + *ch = (utf32_t)(str[0] & 0x07) << 18; + *ch |= (utf32_t)(str[1] & 0x0f) << 12; + *ch |= (utf32_t)(str[2] & 0x3f) << 6; + *ch |= (utf32_t)(str[3] & 0x3f); + if (*ch < 0x010000) return UTF_ERR; + if (*ch > 0x10ffff) return UTF_ERR; + return 4; + } else { + return UTF_ERR; + } +} + +int utf8_seek(utf8_t *str, int off, utf32_t *ch) { + int i; + int len = 0; + + if (off < 0) { + off = -off; + for (i=0; i<off; i++) { + len--; + while ((str[len] & 0xc0) == 0x80) len--; + } + } else { + for (i=0; i<off; i++) { + if ((str[len] & 0x80) == 0x00) { + len += 1; + } else if ((str[0] & 0xe0) == 0xc0) { + len += 2; + } else if ((str[0] & 0xf0) == 0xe0) { + len += 3; + } else if ((str[0] & 0xf8) == 0xf0) { + len += 4; + } + } + } + utf8_dec(str + len, ch); + return len; +} + +int utf8_verify(utf8_t *str, int str_size, int *str_len) { + utf32_t ch; + uint8_t ch_l; + int len = 0; + + while (len < str_size) { + if (str_size - len < 4) { + if (((str[len] & 0xf8) == 0xf0) || + (((str[len] & 0xf0) == 0xe0) && (str_size - len < 3)) || + (((str[len] & 0xe0) == 0xc0) && (str_size - len < 2))) { + break; + } + } + ch_l = utf8_dec(str + len, &ch); + if (ch_l > 0) { + if (ch == 0) { + *str_len = len; + return UTF_OK; + } + len += ch_l; + } else { + break; + } + } + *str_len = len; + return UTF_ERR; +} + +int utf16_enc(utf32_t ch, uint8_t *str) { + if (ch <= 0xffff) { + if ((ch >= 0xd800) && (ch <= 0xdfff)) return UTF_ERR; + str[0] = ch >> 8; + str[1] = ch & 0xff; + return 2; + } else if (ch <= 0x10ffff) { + uint16_t hi; + uint16_t lo; + + ch -= 0x10000; + hi = (ch >> 10) + 0xd800; + lo = (ch & 0x3ff) + 0xdc00; + str[0] = hi >> 8; + str[1] = hi & 0xff; + str[2] = lo >> 8; + str[3] = lo & 0xff; + return 4; + } else { + return UTF_ERR; + } +} + +int utf16_dec(uint8_t *str, utf32_t *ch) { + *ch = (str[0] << 8) | str[1]; + if ((*ch >= 0xd800) && (*ch <= 0xdfff)) { + uint16_t hi = *ch; + uint16_t lo; + + if (hi > 0xdbff) return UTF_ERR; + lo = (str[2] << 8) | str[3]; + if ((lo < 0xdc00) || (lo > 0xdfff)) return UTF_ERR; + *ch = (((hi - 0xd800) << 10) | (lo - 0xdc00)) + 0x10000; + return 4; + } else { + return 2; + } +} + +int utf16_seek(uint8_t *str, int off, utf32_t *ch) { + int i; + int len = 0; + uint16_t cu; + + if (off < 0) { + off = -off; + for (i=0; i<off; i++) { + len -= 2; + cu = (str[len] << 8) | str[len + 1]; + if ((cu >= 0xdc00) && (cu <= 0xdfff)) { + len -= 2; + } + } + } else { + for (i=0; i<off; i++) { + cu = (str[len] << 8) | str[len + 1]; + if ((cu >= 0xd800) && (cu <= 0xdbff)) { + len += 4; + } else { + len += 2; + } + } + } + utf16_dec(str + len, ch); + return len; +} diff --git a/fw/fe310/eos/unicode.h b/fw/fe310/eos/unicode.h new file mode 100644 index 0000000..a3b9696 --- /dev/null +++ b/fw/fe310/eos/unicode.h @@ -0,0 +1,17 @@ +#include <stdint.h> + +#define UTF_OK 0 +#define UTF_ERR -1 + +typedef uint8_t utf8_t; +typedef uint16_t utf16_t; +typedef uint32_t utf32_t; + +int utf8_enc(utf32_t ch, utf8_t *str); +int utf8_dec(utf8_t *str, utf32_t *ch); +int utf8_seek(utf8_t *str, int off, utf32_t *ch); +int utf8_verify(utf8_t *str, int str_size, int *str_len); + +int utf16_enc(utf32_t ch, uint8_t *str); +int utf16_dec(uint8_t *str, utf32_t *ch); +int utf16_seek(uint8_t *str, int off, utf32_t *ch); diff --git a/fw/fe310/eos/wifi.c b/fw/fe310/eos/wifi.c new file mode 100644 index 0000000..d58c0eb --- /dev/null +++ b/fw/fe310/eos/wifi.c @@ -0,0 +1,58 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "eos.h" +#include "event.h" +#include "net.h" + +#include "wifi.h" + +static eos_evt_handler_t evt_handler[EOS_WIFI_MAX_MTYPE]; + +static void wifi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { + if ((buffer == NULL) || (len < 1)) { + eos_net_bad_handler(type, buffer, len); + return; + } + + unsigned char mtype = buffer[0]; + if (mtype < EOS_WIFI_MAX_MTYPE) { + evt_handler[mtype](type, buffer, len); + } else { + eos_net_bad_handler(type, buffer, len); + } +} + +void eos_wifi_init(void) { + int i; + + for (i=0; i<EOS_WIFI_MAX_MTYPE; i++) { + evt_handler[i] = eos_net_bad_handler; + } + eos_net_set_handler(EOS_NET_MTYPE_WIFI, wifi_handle_evt); +} + +void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler) { + if (handler == NULL) handler = eos_net_bad_handler; + if (mtype < EOS_WIFI_MAX_MTYPE) evt_handler[mtype] = handler; +} + +void eos_wifi_connect(const char *ssid, const char *pass) { + int ssid_len = strlen(ssid); + int pass_len = strlen(pass); + unsigned char *buffer = eos_net_alloc(); + + buffer[0] = EOS_WIFI_MTYPE_CONNECT; + strcpy(buffer+1, ssid); + buffer[ssid_len+1] = 0; + strcpy(buffer+ssid_len+2, pass); + buffer[ssid_len+pass_len+2] = 0; + eos_net_send(EOS_NET_MTYPE_WIFI, buffer, ssid_len+pass_len+3, 0); +} + +void eos_wifi_disconnect(void) { + unsigned char *buffer = eos_net_alloc(); + buffer[0] = EOS_WIFI_MTYPE_DISCONNECT; + eos_net_send(EOS_NET_MTYPE_WIFI, buffer, 1, 0); +} diff --git a/fw/fe310/eos/wifi.h b/fw/fe310/eos/wifi.h new file mode 100644 index 0000000..732a7a9 --- /dev/null +++ b/fw/fe310/eos/wifi.h @@ -0,0 +1,14 @@ +#include <stdint.h> +#include "event.h" + +#define EOS_WIFI_MTYPE_SCAN 0 +#define EOS_WIFI_MTYPE_CONNECT 1 +#define EOS_WIFI_MTYPE_DISCONNECT 2 + +#define EOS_WIFI_MAX_MTYPE 3 + +void eos_wifi_init(void); +void eos_wifi_set_handler(unsigned char mtype, eos_evt_handler_t handler); + +void eos_wifi_connect(const char *ssid, const char *pass); +void eos_wifi_disconnect(void); |