research application on sending data to headend

Dependencies:   DataStore JobScheduler NetworkServices W5500Interface nanopb protocol

See "main.cpp" documentation on "API Documentation" tab for details about application.

source/jobSchedulesUpload.cpp

Committer:
sgnezdov
Date:
2017-08-11
Revision:
28:7214f7806526
Parent:
20:5b52a42b9a5d

File content as of revision 28:7214f7806526:

#include "jobSchedulesUpload.h"

#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP  "scup"

#include "nanopb/source/protobuf/pb.h"
#include "nanopb/source/protobuf/pb_encode.h"
#include "protocol/source/job.pb.h"
#include <string.h>
#include "LinkedList.h"
#include "scheduler.h"
#include "schedules.h"

bool fillScheduleData(protocol_Job_ScheduleData_t& pbSchedData, JobScheduler::Appointment& apt) {
    JobScheduler::Job* job = apt.GetJob();
    JobScheduler::ISchedule* schedule = job->GetSchedule();
    int schedType = schedule->ScheduleType();
    switch (schedType) {
        case 1: {
            // protocol_ScheduleType_RunOnce case
            tr_debug("encoding RunOnceSchedule");
            JobScheduler::RunOnceSchedule* s = static_cast<JobScheduler::RunOnceSchedule*>(schedule);
            protocol_RunOnceSchedule pbSched;
            pbSched.AtUnixSec = (uint32_t)s->AtTime();
            // Time should've been pushed to Appointment structure in all cases.
            if (pbSched.AtUnixSec != 0) {
                tr_warn("Run once has not be assigned to appointment yet.  AtUnixSec: %d", pbSched.AtUnixSec);
            } else {
                pbSched.AtUnixSec = (uint32_t)apt.GetTime();
            }
            pb_ostream_t stream = pb_ostream_from_buffer(pbSchedData.bytes, sizeof(pbSchedData.bytes));
            pb_encode(&stream, protocol_RunOnceSchedule_fields, &pbSched);
            pbSchedData.size = stream.bytes_written;
            //tr_debug("sizeof(pbSchedData.bytes): %d, AtUnixSec: %d, bytes written: %d", sizeof(pbSchedData.bytes), pbSched.AtUnixSec, stream.bytes_written);
            return true;
        }
        case 2: {
            // protocol_ScheduleType_Periodic case
            tr_debug("encoding RunPeriodicSchedule");
            //JobScheduler::RunPeriodicSchedule* s = static_cast<JobScheduler::RunPeriodicSchedule*>(schedule);
            //protocol_PeriodicSchedule pbSched;
            return true;
        }
        default: {
            tr_error("Unknown schedule type %d", schedType);
            return false;
        }
    }
}

void JobSchedulesUpload::Run() {
    tr_info("Job Schedules Upload");
    
    // if used on the stack like:
    // protocol_JobList* pbJobsPtr = protocol_JobList_init_zero;
    // the code terminates with error:
    //     CMSIS-RTOS error: Stack underflow (status: 0x1, task ID: 0x20002464, task name: )
    // shortly after quitting this function.
    //
    // Bob P recommendation: try static as a solution.
    
    // protocol_JobList pbJobsPtr; /// = new protocol_JobList(); // protocol_JobList_init_zero;
    
    protocol_JobList* pbJobsPtr = new protocol_JobList(); // protocol_JobList_init_zero;
    protocol_JobList& pbJobs = *pbJobsPtr;
    //tr_debug("pbJobs size: %d", sizeof(pbJobs));
    
    strcpy(pbJobs.sn, this->_conf.SerialNumber());
    
    {
        LinkedList<JobScheduler::Appointment> apts;
        this->_scheduler.AppointmentList(apts);
        node<JobScheduler::Appointment>* aptn = apts.pop(1);
        int idx = 0;
        pbJobs.items_count = 0;
        while (aptn != NULL) {
            JobScheduler::Appointment* apt = aptn->data;
            JobScheduler::Job* job = apt->GetJob();
            tr_debug("adding job ID: %d, type: %d\n", job->GetID(), job->GetTypeID());
            pbJobs.items[idx].ID = job->GetID();
            pbJobs.items[idx].TypeID = job->GetTypeID();
            pbJobs.items[idx].ScheduleTypeID = static_cast<protocol_ScheduleType>(job->GetSchedule()->ScheduleType());
            // pbJobs.items[idx].ScheduleData = 
            if (!fillScheduleData(pbJobs.items[idx].ScheduleData, *apt)) {
                tr_error("job error: failed to fill schedule");
                return;
            }
            //tr_debug("schedule data size: %d", pbJobs.items[idx].ScheduleData.size);
            // pbJobs.items[idx].Data = 
            idx++;
            pbJobs.items_count = idx;
            
            apts.remove(1);
            aptn = apts.pop(1);
        }
        if (idx == 0) {
            tr_info("There are no jobs to send.");
        }
    }
    
    // encode to nothing to detect buffer size
    pb_ostream_t sizeStream = {0};
    pb_encode(&sizeStream, protocol_JobList_fields, &pbJobs);

    // allocate output buffer and encode into it
    uint8_t* outBuf = new uint8_t[sizeStream.bytes_written];
    pb_ostream_t outStream = pb_ostream_from_buffer(outBuf, sizeStream.bytes_written);
    pb_encode(&outStream, protocol_JobList_fields, &pbJobs);
        
    tr_array(outBuf, outStream.bytes_written);

    // send CoAP message
    time_t now = time(NULL);
    
    //uint8_t msg[] = { 0x0a, 0x07, 0x4e, 0x75, 0x63, 0x6c, 0x65, 0x6f, 0x31 };
    //size_t msgLen = 9;
    //_lce.SendV1("/uw/joblist", msg, msgLen, false, now);
    
    _lce.SendV1("/uw/joblist", outBuf, outStream.bytes_written, false, now);
    delete outBuf;
    delete pbJobsPtr;
}