summaryrefslogtreecommitdiff
path: root/src/components/ble/FSService.cpp
blob: 2cfd5ccd298d7ee182d4e627f7735b566347c137 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <nrf_log.h>
#include "FSService.h"
#include "components/ble/BleController.h"

using namespace Pinetime::Controllers;

constexpr ble_uuid128_t FSService::fsServiceUuid;
constexpr ble_uuid128_t FSService::fsVersionUuid;
constexpr ble_uuid128_t FSService::fsTransferUuid;

int FSServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
  auto* fsService = static_cast<FSService*>(arg);
  return fsService->OnFSServiceRequested(conn_handle, attr_handle, ctxt);
}

FSService::FSService(Pinetime::Controllers::FS& fs)
  : fs {fs},
    characteristicDefinition {{.uuid = &fsVersionUuid.u,
                               .access_cb = FSServiceCallback,
                               .arg = this,
                               .flags = BLE_GATT_CHR_F_READ,
                               .val_handle = &versionCharacteristicHandle},
                              {
                                .uuid = &fsTransferUuid.u,
                                .access_cb = FSServiceCallback,
                                .arg = this,
                                .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
                                .val_handle = &transferCharacteristicHandle,
                              },
                              {0}},
    serviceDefinition {
      {/* Device Information Service */
       .type = BLE_GATT_SVC_TYPE_PRIMARY,
       .uuid = &fsServiceUuid.u,
       .characteristics = characteristicDefinition},
      {0},
    } {
}

void FSService::Init() {
  int res = 0;
  res = ble_gatts_count_cfg(serviceDefinition);
  ASSERT(res == 0);

  res = ble_gatts_add_svcs(serviceDefinition);
  ASSERT(res == 0);
}

int FSService::OnFSServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
  if (attributeHandle == versionCharacteristicHandle) {
    NRF_LOG_INFO("FS_S : handle = %d", versionCharacteristicHandle);
    int res = os_mbuf_append(context->om, &fsVersion, sizeof(fsVersion));
    return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  }
  if (attributeHandle == transferCharacteristicHandle) {
    return FSCommandHandler(connectionHandle, context->om);
  }
  return 0;
}

int FSService::FSCommandHandler(uint16_t connectionHandle, os_mbuf* om) {
  auto command = static_cast<commands>(om->om_data[0]);
  NRF_LOG_INFO("[FS_S] -> FSCommandHandler");

  switch (command) {
    case commands::LISTDIR: {
      NRF_LOG_INFO("[FS_S] -> ListDir");
      ListDirHeader *header = (ListDirHeader *)&om->om_data[0];
      uint16_t plen = header->pathlen;
      char path[plen+1] = {0};
      memcpy(path, header->pathstr, plen);
      NRF_LOG_INFO("[FS_S] -> DIR %.10s", path);
      lfs_dir_t dir;
      struct lfs_info info;

      ListDirResponse resp;
      resp.command = 0x51; // LISTDIR_ENTRY;
      resp.status = 1;     // TODO actually use res above!
      resp.totalentries = 0;
      resp.entry = 0;
      int res = fs.DirOpen(path, &dir);
      while (fs.DirRead(&dir, &info)) {
        resp.totalentries++;
      }
      NRF_LOG_INFO("[FS_S] -> %d ", resp.totalentries);
      fs.DirClose(&dir);
      fs.DirOpen(path, &dir);
      while (fs.DirRead(&dir, &info)) {
        switch(info.type){
          case LFS_TYPE_REG:
          {
            resp.flags = 0;
            resp.file_size = info.size;
            break;
          } 
          case LFS_TYPE_DIR:
          {
             resp.flags = 1; 
             resp.file_size = 0;
             break;
          }
        }
        resp.modification_time = 0; // TODO Does LFS actually support TS?
        strcpy(resp.path,info.name);
        resp.path_length = strlen(info.name);
        NRF_LOG_INFO("[FS_S] ->Path %s ,", info.name);
        auto* om = ble_hs_mbuf_from_flat(&resp,sizeof(ListDirResponse));
        ble_gattc_notify_custom(connectionHandle,transferCharacteristicHandle,om);
        resp.entry++;
      }
      resp.entry++;
      resp.file_size = 0;
      resp.path_length = 0;
      resp.flags = 0;
      //Todo this better
      auto* om = ble_hs_mbuf_from_flat(&resp,sizeof(ListDirResponse)-70+resp.path_length);
      ble_gattc_notify_custom(connectionHandle,transferCharacteristicHandle,om);
      NRF_LOG_INFO("[FS_S] -> done ");
    }
  }
  return 0;
}