Merge #244 into sdk602patch0521 from refs/changes/244/head 249/target/1 250/target/1 251/target/1
author彭磊 <1624952103@qq.com>
Sat, 8 Jun 2024 09:38:28 +0000 (09:38 +0000)
committersnickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
Sat, 8 Jun 2024 09:38:28 +0000 (09:38 +0000)
添加蓝牙产测麦克风测试项,添加tar保存exc文件功能

* refs/changes/244/head: (6 commits squashed)

  - 添加蓝牙产测麦克风测试项,添加tar保存exc文件功能

  - Merge branch &#39;sdk602patch0521&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into remotes/origin/sdk602patch0521

  - 补交

  - 补交

  - Merge branch &#39;sdk602patch0521&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into remotes/origin/sdk602patch0521

  - 优化麦克风蓝牙产测,优化tar保存死机文件

Signed-off-by: aliyun6865282430 <1624952103@qq.com>
Reviewed-by: snickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
Merged-by: snickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/244
16 files changed:
code/sdk/application/brandy/brandy_standard/main.c
code/sdk/application/brandy/brandy_standard/thread_pri_init.c
code/sdk/application/wearable/fd230app/nativeui/alarm/src/AlarmClockModel.cpp
code/sdk/application/wearable/fd230app/nativeui/producttest/include/testmicrophoneC.h [new file with mode: 0644]
code/sdk/application/wearable/fd230app/nativeui/producttest/include/testspeakerC.h [deleted file]
code/sdk/application/wearable/fd230app/nativeui/producttest/src/testmicrophone.cpp
code/sdk/application/wearable/fd230app/nativeui/producttest/src/testspeak.cpp
code/sdk/application/wearable/service/factorytest_service/factorytest_protocol.c
code/sdk/drivers/peripheral/cywee/CMakeLists.txt
code/sdk/drivers/peripheral/cywee/src/custom_factory_core.c
code/sdk/drivers/peripheral/cywee/src/main_dml.c
code/sdk/drivers/peripheral/utils/CMakeLists.txt
code/sdk/drivers/peripheral/utils/custom_utils.c
code/sdk/drivers/peripheral/utils/custom_utils.h
code/sdk/drivers/peripheral/utils/microtar.c [new file with mode: 0644]
code/sdk/drivers/peripheral/utils/microtar.h [new file with mode: 0644]

index 53f6f28..c51fe12 100755 (executable)
@@ -36,6 +36,9 @@ void app_main(const void *startup_details_table, const uint32_t density)
 
     board_init(ssb_to_app_table.ssb_to_application_flash_id, ssb_to_app_table.ssb_to_application_flash_unique_id);
 
+    //cywee 烧写密钥
+    //reburn_second_dev();
+    
     service_init();
 
     thread_pri_init();
index 8be0240..a2a7353 100755 (executable)
@@ -344,6 +344,7 @@ static void thread_main(const void *unused)
 {\r
     PRINT("thread_main start "NEWLINE);\r
     unused(unused);\r
+\r
     rc_calibration_func_notify();\r
     bt_acore_btc_ipc_receive_init();\r
     uapi_pm_control(PM_BT_POWER_UP_AND_RUN);\r
index d01e843..b3a92ff 100644 (file)
@@ -714,7 +714,7 @@ int AlarmClockModel::AlarmPlayerStat()
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AlarmClockModel::AlarmPlayerStat playerCtr nullptr");
         return OHOS_FAILURE;
     }
-    playerCtr->SetPlayerCallback(playerCallback);
+    //playerCtr->SetPlayerCallback(playerCallback);
     // 申请资源
     source = std::make_shared<Source>(uri, header);
     if (source.get() == nullptr) {
diff --git a/code/sdk/application/wearable/fd230app/nativeui/producttest/include/testmicrophoneC.h b/code/sdk/application/wearable/fd230app/nativeui/producttest/include/testmicrophoneC.h
new file mode 100644 (file)
index 0000000..d7bf6e0
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-06-07 11:18:25
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2024-06-08 17:28:26
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/producttest/include/testmicrophoneC.h
+ * @Description: 
+ * 
+ * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
+ */
+#ifndef TEST_MICROPHONEC_H
+#define TEST_MICROPHONEC_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C"
+{
+#endif
+#endif
+    void microhone_switch(bool isopen);
+    void check_spk(bool isopen);
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif
+#endif
diff --git a/code/sdk/application/wearable/fd230app/nativeui/producttest/include/testspeakerC.h b/code/sdk/application/wearable/fd230app/nativeui/producttest/include/testspeakerC.h
deleted file mode 100644 (file)
index c2f411c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef TEST_SPEAKERC_H
-#define TEST_SPEAKERC_H
-
-#ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif
-#endif
-    int check_speaker(bool isopen);
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif
-#endif
-#endif
index 27616e0..494b2cc 100644 (file)
@@ -50,6 +50,7 @@ namespace OHOS
                 delete Title;
                 Title=nullptr;
             }
+            AlarmClockModel::GetInstance()->AlarmPlayerStop();
             delete testmakephoneScrollView;
             testmakephoneScrollView=nullptr;
         }
@@ -88,7 +89,7 @@ namespace OHOS
 
 
     uint8_t makphone_falg=0;
-    static char *Path= "/user/music/microphone.mp3";
+    static char *Path= "/user/userdata/microphone.mp3";
     void testmicrohoneView::buttoncallback()
     {
         if(button!=NULL)
@@ -97,7 +98,7 @@ namespace OHOS
             if(makphone_falg==0)
             {
                 char *args[6] = {0};
-                const char *defaultArgs[6] = {"01", "mp3", "16000", "1", "16","/user/music/microphone.mp3"}; // 默认参数数组
+                const char *defaultArgs[6] = {"01", "mp3", "16000", "1", "16","/user/userdata/microphone.mp3"}; // 默认参数数组
 
                 for (int i = 0; i < 6; ++i)
                 {
@@ -117,7 +118,7 @@ namespace OHOS
                 button->SetText("play");
                 makphone_falg++;
 
-                FILE *file =fopen("/user/music/microphone.mp3","rb");
+                FILE *file =fopen("/user/userdata/microphone.mp3","rb");
                 if(file==NULL)
                 {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ffffffffffffffffsssssss");
@@ -204,4 +205,57 @@ namespace OHOS
         }
         return testmakephoneScrollView;
     }
+
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+    void microhone_switch(bool isopen)
+    {
+        char *args[6] = {0};
+        const char *defaultArgs[6] = {"01", "mp3", "16000", "1", "16","/user/userdata/microphone.mp3"}; // 默认参数数组
+
+        int32_t argc = 1;
+        uint8_t *argv = (uint8_t*)"stop";
+
+        if(isopen)
+        {
+            for (int i = 0; i < 6; ++i)
+            {
+                args[i] = (char *)malloc(64);        
+                sprintf(args[i], "%s", defaultArgs[i]);
+            }
+            AudioCaptureSample(6, (const char **)args);
+        }
+        else
+        {
+            AudioCaptureSample(argc, (const char **)&argv);
+            FILE *file =fopen("/user/userdata/microphone.mp3","rb");
+            if(file==NULL)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ffffffffffffffffsssssss");
+            }
+            fclose(file);
+        }
+    }
+
+    void check_spk(bool isopen)
+    {
+        if(isopen)
+            AlarmClockModel::GetInstance()->testPlayerStart("/user/userdata/microphone.mp3");
+        else
+            AlarmClockModel::GetInstance()->AlarmPlayerStop();
+    }
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+
 }
\ No newline at end of file
index 75fa996..2347aa6 100644 (file)
@@ -228,24 +228,4 @@ namespace OHOS
         }
         return testSPEAKScrollView;
     }
-
-    #ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-#endif /* __cplusplus */
-
-    int check_speaker(bool isopen)
-    {
-        if(isopen)
-            return AlarmClockModel::GetInstance()->AlarmPlayerStart();
-        else
-            return AlarmClockModel::GetInstance()->AlarmPlayerStop();
-    }
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* __cplusplus */
 }
index d4ced75..af5956d 100644 (file)
@@ -1466,11 +1466,10 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint
         case BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER:\r
             if(testitem == 0x01)\r
             {\r
-\r
                 uint8_t send_data= 0;\r
 \r
-                uapi_check_speaker(1);\r
-                \r
+                uapi_microhone_switch(1);\r
+ \r
                 factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
                         BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER,\r
                         0x01,\r
@@ -1481,13 +1480,37 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint
 \r
                 uint8_t send_data = 0;\r
 \r
-                uapi_check_speaker(0);;\r
+                uapi_microhone_switch(0);\r
                 \r
                 factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
                         BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER,\r
                         0x02,\r
                         &send_data,\r
                         1);\r
+            } else if(testitem == 0x03)\r
+            {\r
+\r
+                uint8_t send_data = 0;\r
+\r
+                uapi_check_spk(1);\r
+                \r
+                factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
+                        BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER,\r
+                        0x03,\r
+                        &send_data,\r
+                        1);\r
+            } else if(testitem == 0x04)\r
+            {\r
+\r
+                uint8_t send_data = 0;\r
+\r
+                uapi_check_spk(0);\r
+                \r
+                factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
+                        BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER,\r
+                        0x04,\r
+                        &send_data,\r
+                        1);\r
             }\r
             break;\r
 \r
index 30b9399..aa4808b 100644 (file)
@@ -53,7 +53,7 @@ if("SUPPORT_AT_CYWEE" IN_LIST DEFINES)
     find_library(LIB_PATH_CWM_LIB_DML Lib/CWM_LIB_DML_clang_riscv.a ${CMAKE_CURRENT_SOURCE_DIR})
     find_library(LIB_PATH_CWM_LIB Lib/CWM_LIB_clang_riscv.a ${CMAKE_CURRENT_SOURCE_DIR})
     target_link_libraries(${TARGET_NAME} PRIVATE -Wl,--whole-archive ${LIB_PATH_CWM_LIB_DML} ${LIB_PATH_CWM_LIB} PRIVATE -Wl,--whole-archive)
-endif()
     #target_link_libraries(${TARGET_NAME} PRIVATE -Wl,--whole-archive  ${LIB_PATH_CWM_LIB} PRIVATE -Wl,--whole-archive)
-#endif()
+endif()
+
 build_component()
index 5107e1e..915139a 100644 (file)
@@ -78,11 +78,9 @@ int reburn_second_dev(void) {
     int len = 0, ret = 0;\r
 \r
     impl_prepare(&m_var);\r
+    printf("[reburn_second_dev] Built at %s %s\n", __DATE__, __TIME__);\r
 \r
-    reburn_log_printf("[reburn_second_dev] Built at %s %s\n", __DATE__, __TIME__);\r
-    printf("[reburn_second_dev] Built at \r\n");\r
     if (!impl_checkMcuModel()) {\r
-        reburn_log_printf("cannot reburn: wrong model\n");\r
         printf("cannot reburn: wrong model \r\n");\r
         return STS_ERR_WRONG_MODEL;\r
     }\r
@@ -91,11 +89,9 @@ int reburn_second_dev(void) {
     scl.iData[0] = 1;\r
     CWM_SettingControl(SCL_GET_LIB_INFO, &scl);\r
     if (scl.iData[5] < 3000) {\r
-        reburn_log_printf("%d Not a valid reburn library\n", scl.iData[5]);\r
         printf("%d Not a valid reburn library\n", scl.iData[5]);\r
         return STS_ERR_INVALID_LIB;\r
     }\r
-    reburn_log_printf("model:%s version:%d.%d.%d.%d product:%d\n", m_var.chip_name, scl.iData[1], scl.iData[2], scl.iData[3], scl.iData[4], scl.iData[5]);\r
     printf("model:%s version:%d.%d.%d.%d product:%d\n", m_var.chip_name, scl.iData[1], scl.iData[2], scl.iData[3], scl.iData[4], scl.iData[5]);\r
 \r
     impl_sec_env_init();\r
index 75961a9..f6b61b2 100644 (file)
@@ -704,9 +704,6 @@ void CWM_AP_dmlSensorDataOutput_listen(const dml_sensorData_t * pSdo) {
 }
 #endif
 
-// int cm__hs1__init(void);
-// int cm__hs1__deinit(void);
-
 int cywee_main_dml(void) 
 {
     if (cywee_installized == 1)
@@ -716,7 +713,7 @@ int cywee_main_dml(void)
     }
 
     cywee_installized = 1;
-    //reburn_second_dev();
+
     int i;
     memset(&scl, 0, sizeof(scl));
     scl.iData[0] = 1;
index 4608584..1977a4e 100644 (file)
@@ -10,6 +10,7 @@ set(SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/custom_cmd_service.c
     ${CMAKE_CURRENT_SOURCE_DIR}/custom_runtime.c
     ${CMAKE_CURRENT_SOURCE_DIR}/pdu.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/microtar.c
 )
 
 set(PUBLIC_HEADER
index 2688857..7bc3292 100644 (file)
@@ -27,7 +27,7 @@
 #ifdef FD230
 #include "soundandvibration/include/SoundAndVibrationVolumeSettingC.h"
 #include "networkandcall/include/NetworkAndCallC.h"
-#include "producttest/include/testspeakerC.h"
+#include "producttest/include/testmicrophoneC.h"
 #endif
 #include <dirent.h>
 #include <unistd.h>
@@ -47,6 +47,7 @@
 
 #include "custom_utils.h"
 #include "cywee_service.h"
+#include "microtar.h"
 
 errcode_t uapi_create_osThread_custom(app_task_definition_t *task_cfg)
 {
@@ -293,10 +294,16 @@ bool stop_alipay_ble_service(void)
 }
 void startup_post_init_task(void)
 {
-
     PRINT("startup_post_init_task !\r\n");
+
     uapi_calendar_recover_date();
 
+    int ret = uapi_save_exc();
+    if(ret != 0)
+        PRINT("exc file save failed \r\n");
+    else
+        PRINT("exc file save succed \r\n");
+
     if(!custom_ble_service_on_flag())
     {
         stop_custom_ble_service();
@@ -337,7 +344,7 @@ void startup_post_init(void)
     taskcfg.create_queue_handle = NULL;
     taskcfg.attr.name="startup_post_init_task";
     taskcfg.attr.priority = osPriorityNormal;
-    taskcfg.attr.stack_size = 0x1000;
+    taskcfg.attr.stack_size = 0x1100;
     taskcfg.func = startup_post_init_task;
     taskcfg.use_mem = USE_EXTEND_MEM;
     
@@ -1510,6 +1517,12 @@ int removeFilesInFolder(const char *folderPath)
     struct stat s_buf;
     int ret = 0;
 
+    if(access(folderPath, F_OK) == -1)
+    {
+        PRINT("%s does not exist!!!\r\n", folderPath);
+        return -1;
+    }
+
     dir = opendir(folderPath);
     if (dir == NULL) 
     {
@@ -1568,6 +1581,95 @@ void uapi_delete_files(void)
     }
 }
 
+int uapi_save_exc(void)
+{
+    const char *folderPath = "/user/exc";
+    const char *tarPath = "/user/tar";
+    const char *tarfilePath = "/user/tar/exc_%d.tar";
+
+    DIR *dir;
+    struct dirent *entry;
+    mtar_t tar;
+    char buffer[1024];
+    size_t bytesRead = 0;
+    FILE *fp;
+    struct stat file_inf;
+    int ret = 0;
+
+    dir = opendir(folderPath);
+    if (dir == NULL) 
+    {
+        PRINT("unable to open %s\r\n",folderPath);
+        return -1;
+    }
+
+    if(access(tarPath, F_OK) == -1)
+    {
+        ret = mkdir(tarPath, 0777); 
+        if(ret == -1)
+        {
+            PRINT("mkdir %s failed \r\n",tarPath);
+            return -1;
+        }
+    }
+
+    uint32_t timestamp = get_local_timestamp();
+    char *str = (char *)malloc(200);
+    memset_s(str, 200, 0, 200);
+    sprintf(str, tarfilePath, timestamp);
+
+    ret = mtar_open(&tar, str, "w");
+    if (ret != MTAR_ESUCCESS) 
+    {
+        PRINT("unable to open/create %s\r\n",str);
+        return -1;
+    }
+
+    while ((entry = readdir(dir)) != NULL) 
+    {
+        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) 
+        {
+            char filePath[64];
+            snprintf(filePath, sizeof(filePath), "%s/%s", folderPath, entry->d_name);
+
+            fp = fopen(filePath, "r");
+            if(fp == NULL) 
+            {
+                PRINT("uable to open %s\r\n", filePath);
+                return -1;
+            }
+
+            memset(&file_inf, 0, sizeof(file_inf));
+            stat(filePath, &file_inf);
+            
+            mtar_write_file_header(&tar, entry->d_name, file_inf.st_size);
+
+            while((bytesRead = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+            {
+                mtar_write_data(&tar, buffer, bytesRead);
+                
+                memset(buffer, 0, sizeof(buffer));
+
+                if (bytesRead < 1024 && !feof(fp)) 
+                    continue;
+
+                if (feof(fp)) 
+                {
+                    fclose(fp);
+                    break;
+                }
+            }
+        }
+    }
+
+    /* Finalize -- this needs to be the last thing done before closing */
+    mtar_finalize(&tar);
+
+    /* Close archive */
+    mtar_close(&tar);
+    closedir(dir);
+    return ret;
+}
 
 #include "driver/calendar.h"
 
@@ -2002,9 +2104,16 @@ int custom_exit_lpm(void)
 }
 #endif
 
-int uapi_check_speaker(bool isopen)
+void uapi_microhone_switch(bool isopen)
+{
+    #ifdef FD230
+        microhone_switch(isopen);
+    #endif
+}
+
+void uapi_check_spk(bool isopen)
 {
     #ifdef FD230
-        return check_speaker(isopen);
+        check_spk(isopen);
     #endif
 }
\ No newline at end of file
index 1e02923..625f34e 100644 (file)
@@ -190,6 +190,11 @@ void uapi_cywee_set_user_info(int user_info[5]);
 void uapi_cywee_time_sync(void);
 void uapi_cywee_get_chipinfo(char *databuf,uint8_t len);
 void uapi_ppg_get_id(uint8_t *chip_id);
+
+
+void uapi_microhone_switch(bool isopen);
+void uapi_check_spk(bool isopen);
+
 #include "custom_utilscpp.h"
 
 
diff --git a/code/sdk/drivers/peripheral/utils/microtar.c b/code/sdk/drivers/peripheral/utils/microtar.c
new file mode 100644 (file)
index 0000000..2e5bc40
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2017 rxi
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "microtar.h"
+
+typedef struct {
+    char name[100];
+    char mode[8];
+    char owner[8];
+    char group[8];
+    char size[12];
+    char mtime[12];
+    char checksum[8];
+    char type;
+    char linkname[100];
+    char _padding[255];
+} mtar_raw_header_t;
+
+
+static unsigned round_up(unsigned n, unsigned incr) {
+    return n + (incr - n % incr) % incr;
+}
+
+
+static unsigned checksum(const mtar_raw_header_t* rh) {
+    unsigned i;
+    unsigned char *p = (unsigned char*) rh;
+    unsigned res = 256;
+    for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) 
+    {
+        res += p[i];
+    }
+    for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) 
+    {
+        res += p[i];
+    }
+    return res;
+}
+
+
+static int tread(mtar_t *tar, void *data, unsigned size) 
+{
+    int err = tar->read(tar, data, size);
+    tar->pos += size;
+    return err;
+}
+
+
+static int twrite(mtar_t *tar, const void *data, unsigned size) 
+{
+    int err = tar->write(tar, data, size);
+    tar->pos += size;
+    return err;
+}
+
+
+static int write_null_bytes(mtar_t *tar, int n) 
+{
+    int i, err;
+    char nul = '\0';
+    for (i = 0; i < n; i++) 
+    {
+        err = twrite(tar, &nul, 1);
+        if (err) 
+        {
+            return err;
+        }
+    }
+    return MTAR_ESUCCESS;
+}
+
+
+static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) 
+{
+    unsigned chksum1, chksum2;
+
+    /* If the checksum starts with a null byte we assume the record is NULL */
+    if (*rh->checksum == '\0') 
+    {
+        return MTAR_ENULLRECORD;
+    }
+
+    /* Build and compare checksum */
+    chksum1 = checksum(rh);
+    sscanf(rh->checksum, "%o", &chksum2);
+    if (chksum1 != chksum2) 
+    {
+        return MTAR_EBADCHKSUM;
+    }
+
+    /* Load raw header into header */
+    sscanf(rh->mode, "%o", &h->mode);
+    sscanf(rh->owner, "%o", &h->owner);
+    sscanf(rh->size, "%o", &h->size);
+    sscanf(rh->mtime, "%o", &h->mtime);
+    h->type = rh->type;
+    strcpy(h->name, rh->name);
+    strcpy(h->linkname, rh->linkname);
+
+    return MTAR_ESUCCESS;
+}
+
+
+static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) 
+{
+    unsigned chksum;
+
+    /* Load header into raw header */
+    memset(rh, 0, sizeof(*rh));
+    sprintf(rh->mode, "%o", h->mode);
+    sprintf(rh->owner, "%o", h->owner);
+    sprintf(rh->size, "%o", h->size);
+    sprintf(rh->mtime, "%o", h->mtime);
+    rh->type = h->type ? h->type : MTAR_TREG;
+    strcpy(rh->name, h->name);
+    strcpy(rh->linkname, h->linkname);
+
+    /* Calculate and write checksum */
+    chksum = checksum(rh);
+    sprintf(rh->checksum, "%06o", chksum);
+    rh->checksum[7] = ' ';
+
+    return MTAR_ESUCCESS;
+}
+
+
+const char* mtar_strerror(int err) 
+{
+    switch (err) 
+    {
+        case MTAR_ESUCCESS     : return "success";
+        case MTAR_EFAILURE     : return "failure";
+        case MTAR_EOPENFAIL    : return "could not open";
+        case MTAR_EREADFAIL    : return "could not read";
+        case MTAR_EWRITEFAIL   : return "could not write";
+        case MTAR_ESEEKFAIL    : return "could not seek";
+        case MTAR_EBADCHKSUM   : return "bad checksum";
+        case MTAR_ENULLRECORD  : return "null record";
+        case MTAR_ENOTFOUND    : return "file not found";
+    }
+    return "unknown error";
+}
+
+
+static int file_write(mtar_t *tar, const void *data, unsigned size) {
+  unsigned res = fwrite(data, 1, size, tar->stream);
+  return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
+}
+
+static int file_read(mtar_t *tar, void *data, unsigned size) {
+  unsigned res = fread(data, 1, size, tar->stream);
+  return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
+}
+
+static int file_seek(mtar_t *tar, unsigned offset) {
+  int res = fseek(tar->stream, offset, SEEK_SET);
+  return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
+}
+
+static int file_close(mtar_t *tar) {
+  fclose(tar->stream);
+  return MTAR_ESUCCESS;
+}
+
+
+int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
+  int err;
+  mtar_header_t h;
+
+  /* Init tar struct and functions */
+  memset(tar, 0, sizeof(*tar));
+  tar->write = file_write;
+  tar->read = file_read;
+  tar->seek = file_seek;
+  tar->close = file_close;
+
+  /* Assure mode is always binary */
+  if ( strchr(mode, 'r') ) mode = "rb";
+  if ( strchr(mode, 'w') ) mode = "wb";
+  if ( strchr(mode, 'a') ) mode = "ab";
+  /* Open file */
+  tar->stream = fopen(filename, mode);
+  if (!tar->stream) {
+    return MTAR_EOPENFAIL;
+  }
+  /* Read first header to check it is valid if mode is `r` */
+  if (*mode == 'r') {
+    err = mtar_read_header(tar, &h);
+    if (err != MTAR_ESUCCESS) {
+      mtar_close(tar);
+      return err;
+    }
+  }
+
+  /* Return ok */
+  return MTAR_ESUCCESS;
+}
+
+
+int mtar_close(mtar_t *tar) {
+  return tar->close(tar);
+}
+
+
+int mtar_seek(mtar_t *tar, unsigned pos) {
+  int err = tar->seek(tar, pos);
+  tar->pos = pos;
+  return err;
+}
+
+
+int mtar_rewind(mtar_t *tar) {
+  tar->remaining_data = 0;
+  tar->last_header = 0;
+  return mtar_seek(tar, 0);
+}
+
+
+int mtar_next(mtar_t *tar) {
+  int err, n;
+  mtar_header_t h;
+  /* Load header */
+  err = mtar_read_header(tar, &h);
+  if (err) {
+    return err;
+  }
+  /* Seek to next record */
+  n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
+  return mtar_seek(tar, tar->pos + n);
+}
+
+
+int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
+  int err;
+  mtar_header_t header;
+  /* Start at beginning */
+  err = mtar_rewind(tar);
+  if (err) {
+    return err;
+  }
+  /* Iterate all files until we hit an error or find the file */
+  while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
+    if ( !strcmp(header.name, name) ) {
+      if (h) {
+        *h = header;
+      }
+      return MTAR_ESUCCESS;
+    }
+    mtar_next(tar);
+  }
+  /* Return error */
+  if (err == MTAR_ENULLRECORD) {
+    err = MTAR_ENOTFOUND;
+  }
+  return err;
+}
+
+
+int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
+  int err;
+  mtar_raw_header_t rh;
+  /* Save header position */
+  tar->last_header = tar->pos;
+  /* Read raw header */
+  err = tread(tar, &rh, sizeof(rh));
+  if (err) {
+    return err;
+  }
+  /* Seek back to start of header */
+  err = mtar_seek(tar, tar->last_header);
+  if (err) {
+    return err;
+  }
+  /* Load raw header into header struct and return */
+  return raw_to_header(h, &rh);
+}
+
+
+int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
+  int err;
+  /* If we have no remaining data then this is the first read, we get the size,
+   * set the remaining data and seek to the beginning of the data */
+  if (tar->remaining_data == 0) {
+    mtar_header_t h;
+    /* Read header */
+    err = mtar_read_header(tar, &h);
+    if (err) {
+      return err;
+    }
+    /* Seek past header and init remaining data */
+    err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
+    if (err) {
+      return err;
+    }
+    tar->remaining_data = h.size;
+  }
+  /* Read data */
+  err = tread(tar, ptr, size);
+  if (err) {
+    return err;
+  }
+  tar->remaining_data -= size;
+  /* If there is no remaining data we've finished reading and seek back to the
+   * header */
+  if (tar->remaining_data == 0) {
+    return mtar_seek(tar, tar->last_header);
+  }
+  return MTAR_ESUCCESS;
+}
+
+
+int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
+  mtar_raw_header_t rh;
+  /* Build raw header and write */
+  header_to_raw(&rh, h);
+  tar->remaining_data = h->size;
+  return twrite(tar, &rh, sizeof(rh));
+}
+
+
+int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
+  mtar_header_t h;
+  /* Build header */
+  memset(&h, 0, sizeof(h));
+  strcpy(h.name, name);
+  h.size = size;
+  h.type = MTAR_TREG;
+  h.mode = 0664;
+  /* Write header */
+  return mtar_write_header(tar, &h);
+}
+
+
+int mtar_write_dir_header(mtar_t *tar, const char *name) {
+  mtar_header_t h;
+  /* Build header */
+  memset(&h, 0, sizeof(h));
+  strcpy(h.name, name);
+  h.type = MTAR_TDIR;
+  h.mode = 0775;
+  /* Write header */
+  return mtar_write_header(tar, &h);
+}
+
+
+int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
+  int err;
+  /* Write data */
+  err = twrite(tar, data, size);
+  if (err) {
+    return err;
+  }
+  tar->remaining_data -= size;
+  /* Write padding if we've written all the data for this file */
+  if (tar->remaining_data == 0) {
+    return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
+  }
+  return MTAR_ESUCCESS;
+}
+
+
+int mtar_finalize(mtar_t *tar) {
+  /* Write two NULL records */
+  return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
+}
\ No newline at end of file
diff --git a/code/sdk/drivers/peripheral/utils/microtar.h b/code/sdk/drivers/peripheral/utils/microtar.h
new file mode 100644 (file)
index 0000000..e6e73b4
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2017 rxi
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See `microtar.c` for details.
+ */
+
+#ifndef MICROTAR_H
+#define MICROTAR_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MTAR_VERSION "0.1.0"
+
+enum {
+  MTAR_ESUCCESS     =  0,
+  MTAR_EFAILURE     = -1,
+  MTAR_EOPENFAIL    = -2,
+  MTAR_EREADFAIL    = -3,
+  MTAR_EWRITEFAIL   = -4,
+  MTAR_ESEEKFAIL    = -5,
+  MTAR_EBADCHKSUM   = -6,
+  MTAR_ENULLRECORD  = -7,
+  MTAR_ENOTFOUND    = -8
+};
+
+enum {
+  MTAR_TREG   = '0',
+  MTAR_TLNK   = '1',
+  MTAR_TSYM   = '2',
+  MTAR_TCHR   = '3',
+  MTAR_TBLK   = '4',
+  MTAR_TDIR   = '5',
+  MTAR_TFIFO  = '6'
+};
+
+typedef struct {
+  unsigned mode;
+  unsigned owner;
+  unsigned size;
+  unsigned mtime;
+  unsigned type;
+  char name[100];
+  char linkname[100];
+} mtar_header_t;
+
+
+typedef struct mtar_t mtar_t;
+
+struct mtar_t {
+  int (*read)(mtar_t *tar, void *data, unsigned size);
+  int (*write)(mtar_t *tar, const void *data, unsigned size);
+  int (*seek)(mtar_t *tar, unsigned pos);
+  int (*close)(mtar_t *tar);
+  void *stream;
+  unsigned pos;
+  unsigned remaining_data;
+  unsigned last_header;
+};
+
+
+const char* mtar_strerror(int err);
+
+int mtar_open(mtar_t *tar, const char *filename, const char *mode);
+int mtar_close(mtar_t *tar);
+
+int mtar_seek(mtar_t *tar, unsigned pos);
+int mtar_rewind(mtar_t *tar);
+int mtar_next(mtar_t *tar);
+int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
+int mtar_read_header(mtar_t *tar, mtar_header_t *h);
+int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
+
+int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
+int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
+int mtar_write_dir_header(mtar_t *tar, const char *name);
+int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
+int mtar_finalize(mtar_t *tar);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file